]> sourceware.org Git - libabigail.git/commitdiff
Un-share diff nodes in the comparison IR
authorDodji Seketeli <dodji@redhat.com>
Fri, 26 Dec 2014 12:22:16 +0000 (13:22 +0100)
committerDodji Seketeli <dodji@redhat.com>
Fri, 26 Dec 2014 17:45:06 +0000 (18:45 +0100)
Until now, the diff nodes of the comparison IR were shared.  That is,
two diffs about the same subjects were represented by the same diff
node that would appear twice in the tree.

This was preventing us from spotting e.g, the first occurrence of a
diff node that would later (in the tree) turn to be redundant because
all redundant diff nodes are represented by the same diff node
pointer.

This patch now makes each diff node be different, as far of pointer
comparison is concerned.  But it introduces the concept of canonical
diff node to ease the comparison between two diff nodes.  Two diff
nodes that are equal have the same canonical diff node.

With this facility, it's now possible to tell the difference between
diff nodes that are (structurally) equal.  It's not possible to say
things like "this is the first or second occurrence of the redundant
diff node foo'.

* include/abg-ir.h: Prefix the doc string with "///", rather than
writing it inside a /**/ comment.
* include/abg-comparison.h (function_decl_diff)
(function_decl_diff_sptr, fn_parm_diff, fn_parm_diff_sptr)
(var_diff_sptr, base_diff, class_diff, class_diff_sptr): Move
these class & typedef decls to the top of the file.
(string_changed_base_map, string_changed_parm_map)
(unsigned_changed_parm_map, changed_function_ptr)
(string_changed_function_ptr_map): Remove these typedefs.
(string_base_diff_sptr_map, string_fn_parm_diff_sptr_map)
(unsigned_fn_parm_diff_sptr_map, string_var_diff_sptr_map)
(unsigned_var_diff_sptr_map, string_function_decl_diff_sptr_map)
(string_var_diff_ptr_map): New typedefs.
(diff_context::{has_diff_for,add_diff}): Make these member
functions private.
(diff_context::{set_canonical_diff_for,
set_or_get_canonical_diff_for}): Declare new private member
functions.
(diff_context::{get_canonical_diff_for,
initialize_canonical_diff}): New public member functions.
(diff_context::maybe_apply_filters): Set the default value of the
'traverse_nodes_once' parameter to false.
(compute_diff): Make the overload for class_decl_sptr friend of
the diff_context class.
(class diff): Make the diff_context class a friend of this one.
(diff::set_canonical_diff): Declare new private member function.
(diff::get_canonical_diff): Declare new public member function.
(diff::children_nodes): Make this return a vector<diff_sptr>, rather
than a vector<diff*>.
(diff::append_child_node): Make this take a diff_sptr rather than
a diff*.
(class fn_parm_diff): Declare new type.
(compute_diff): Declare new overload for the new
function_decl::parameter_sptr.
(function_decl_diff::subtype_changed_parms): Return a
string_fn_parm_diff_sptr_map rather than a string_changed_parm.
(function_decl_diff::children_nodes): Return a vector<diff_sptr>.
(function_decl_diff::append_child_node): Take a diff_sptr.
(function_decl_diff::changed_functions): Return a
string_function_decl_diff_sptr_map.
(function_decl_diff::changed_variables): Return a
string_var_diff_sptr.
(class function_decl::parameter): Make this a pimpled class.
Also, make it inherit decl_base.
(equals): New overload for function_decl::parameter.
(struct function_decl::parameter::hash): Declare this.
(ir_node_visitor::visit): Declare new overload for
function_decl::parameter.
* src/abg-comparison.cc: Add doc-string about the internal
representation of the comparison engine and also about the concept
of canonical diff of the comparison engine.
(RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER)
(RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER2)
(RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER3): Consider the
canonical diff when trying to know if the current node was
reported earlier.
(diff_context::priv::canonical_diffs): New data member.
(diff_context::{get_canonical_diff_for, set_canonical_diff_for,
set_or_get_canonical_diff_for, initialize_canonical_diff}): Define
new member functions.
(diff_context::{diff_has_been_traversed, mark_diff_as_traversed):
Consider canonical diff for these tests and actions.
(diff::priv::children_): Change the type of this to
vector<diff_sptr>.
(diff::canonical_diff_): New data member.
(diff::diff): Initialize the diff::canonical_diff_ data member.
(diff::begin_traversing): Mark the canonical diff node too.
(diff::is_traversing): Consider the canonical diff node in this
test.
(diff::end_traversing): Make the canonical diff node too.  Also
mark the current node as having been traversed.
(diff::children_nodes): Return a vector<diff_sptr> type.
(diff::{get_canonical_diff, set_canonical_diff}): Define new
member functions.
(diff::append_child_node): Take a diff_sptr type parameter.
(diff::{reported_once, currently_reporting}): Flag the canonical
diff node too.  And consider the canonical diff node when checking
the flag.
(diff::traverse): No need to mark the node as being traversed
because the diff::end_traversing() function does it now.  Adjust
the code because diff::children_nodes() now returns
vector<diff_sptr>.
({distinct_diff, var_diff, pointer_diff, array_diff,
reference_diff, qualified_type_diff, enum_diff, class_diff,
base_diff, scope_diff, function_decl_diff, typedef_diff,
corpus_diff}::chain_into_hierarchy): Adjust to the new type that
diff::append_child_node() takes.  Also, take into account that the
diff nodes are now un-shared.
(compute_diff_for_distinct_kinds, compute_diff_for_types)
(compute_diff): Do not share diff nodes anymore.  Initialize the
canonical diff node for the new created node.
(represent): Take a var_diff_sptr rather than two var_decl_sptr.
Adjust.  Also take in account the fact that diff nodes are not
shared anymore, and that they do have canonical diffs.
(var_diff::type_diff): Make the computation of the type_diff of
the var_diff be lazy.  This avoids infinite (recursive) creation
of diff nodes when a class diff node has a sub-type of data member
that is a class diff node too.
(var_diff::report): Detect redundant reporting of this kind of
diff node.
(class_diff::priv::changed_bases_): Change the type of this to
string_base_diff_sptr_map.
(class_diff::priv::subtype_changed_dm_): Change the type of this
to string_var_diff_sptr_map.
(class_diff::priv::changed_dm_): Change the type of this to
unsigned_var_diff_sptr_map.
(class_diff::priv::{count_filtered_subtype_changed_dm,
count_filtered_bases}): Do not take a diff_context_sptr anymore.
(class_diff::ensure_lookup_tables_populated): changed_bases_
subtype_changed_dm_ and changed_dm_ are now *NOT* shared diff
nodes anymore.
(class_diff::priv::base_has_changed): Adjust.
(class_diff::priv::subtype_changed_dm): Adjust.
(class_diff::priv::count_filtered_bases): Adjust as changed_bases_
is now a map of un-shared diff nodes.
(class_diff::priv::count_filtered_subtype_changed_dm): Adjust as
subtype_changed_dm_ is now a map of un-shared diff nodes.
(class_diff::priv::{count_filtered_changed_mem_fns,
count_filtered_inserted_mem_fns, count_filtered_deleted_mem_fns,
}): Adjust for change of the default parameter value of
diff_context::maybe_apply_filters().
(class_diff::~class_diff): New destructor.
(class_diff::changed_bases): Return a string_base_diff_sptr_map&
type.
(class_diff::{inserted_data_members, deleted_data_members,
changed_member_fns}): Add doc strings.
(struct changed_data_member_comp): Remove.
(struct var_diff_comp): New comparison functor.
(sort_changed_data_members): Remove.
(sort_var_diffs): Define new sorting function.
(class_diff::report): Adjust.
(fn_parm_diff::*): Define member types and functions of the new
fn_parm_diff type.
(function_decl_diff::priv::{subtype_changed_parms_,
changed_parms_by_id_}): Make these take a map of fn_parm_diff_sptr
nodes.
(function_decl_diff::ensure_lookup_tables_populated): Adjust to
the fact that priv_->subtype_changed_parms_ and
priv_->priv_->changed_parms_by_id_ now are maps of un-shared
fn_parm_diff_sptr nodes.
(function_decl_diff::subtype_changed_parms): Adjust.
(struct changed_parm_comp): Remove.
(struct fn_parm_diff_comp): New comparison functor.
(sort_changed_parm_map): Remove.
(sort_string_fn_parm_diff_sptr_map): New sorting function.
(function_decl_diff::report): Adjust.
(corpus_diff::priv::children_): Change the type of this to
vector<diff_sptr>.
(corpus_diff::priv::changed_fns_): Changed the type of this to
string_function_decl_diff_sptr_map.
(corpus_diff::priv::changed_vars_): Changed the type of this to
string_var_diff_sptr_map.
(corpus_diff::priv::ensure_lookup_tables_populated): Adjust.
(corpus_diff::priv::apply_filters_and_compute_diff_stats}):
Adjust.  Do not need to clear redundancy categorization anymore
because the diff nodes are not shared anymore.
(corpus_diff::priv::categorize_redundant_changed_sub_nodes):
Adjust.
(corpus_diff::priv::clear_redundancy_categorization): Adjust.
(corpus_diff::changed_variables): Adjust.
(struct changed_function_ptr_comp): Remove.
(struct function_decl_diff_comp): New comparison functor.
(sort_string_changed_function_ptr_map): Remove.
(sort_string_function_decl_diff_sptr_map): Define new sorting
function.
(struct changed_vars_comp): Remove.
(struct var_diff_sptr_comp): New comparison functor.
(sort_changed_vars): Remove.
(sort_string_var_diff_sptr_map): Define new sorting function.
(corpus_diff::report): Adjust.
(corpus_diff::traverse): Adjust.
({category_propagation_visitor,
suppression_categorization_visitor}::visit_end): Adjust.
(clear_redundancy_categorization): Adjust.
* src/abg-hash.cc (function_decl::parameter::hash::operator):
Adjust.
* src/abg-ir.cc (struct function_decl::parameter::priv): Define
here as part of pimpl-ifying the function_decl::parameter type.
(function_decl::parameter::*): Define here the member functions as
part of pimpl-ifying the function_decl::parameter type.
(equals): Define the overload for function_decl::parameter here
too.
(ir_node_visitor::visit(function_decl::parameter*)): Define this.
* tests/data/test-abicompat/test0-fn-changed-report-0.txt: Adjust.
* tests/data/test-diff-suppr/test5-fn-suppr-report-0.txt: Adjust.
* tests/data/test-diff-dwarf/libtest21-redundant-fn-v0.so: New
test input data.
* tests/data/test-diff-dwarf/libtest21-redundant-fn-v1.so:
Likewise.
* tests/data/test-diff-dwarf/test21-redundant-fn-v0.cc: Source
code for test input binary above.
* tests/data/test-diff-dwarf/test21-redundant-fn-v1.cc: Likewise.
* tests/data/test-diff-dwarf/test21-redundant-fn-report-0.txt: New
test input data.
* tests/data/test-diff-dwarf/libtest22-changed-parm-c-v0.so: New
test input data.
* tests/data/test-diff-dwarf/libtest22-changed-parm-c-v1.so:
Likewise.
* tests/data/test-diff-dwarf/test22-changed-parm-c-v0.c: Source
code for test input binary above.
* tests/data/test-diff-dwarf/test22-changed-parm-c-v1.c: Likewise.
* tests/test-diff-dwarf.cc (in_out_spec): Add the new test input
data to the vector the test inputs to run this harness over.
* tests/data/test-diff-suppr/test8-redundant-fn-report-0.txt: New
test input data.
* tests/data/test-diff-suppr/test8-redundant-fn-report-1.txt:
Likewise.
* tests/data/test-diff-suppr/libtest8-redundant-fn-v0.so: New test
input binary.
* tests/data/test-diff-suppr/libtest8-redundant-fn-v1.so: Likewise.
* tests/data/test-diff-suppr/test8-redundant-fn-v0.cc: Source code
code for binary test input above.
* tests/data/test-diff-suppr/test8-redundant-fn-v1.cc: Likewise.
* tests/data/test-diff-suppr/test9-changed-parm-c-report-0.txt:
New test input data.
* tests/data/test-diff-suppr/test9-changed-parm-c-report-1.txt:
Likewise.
* tests/data/test-diff-suppr/libtest9-changed-parm-c-v0.so: New
test input binary.
* tests/data/test-diff-suppr/libtest9-changed-parm-c-v1.so: New
test input binary.
* tests/data/test-diff-suppr/test9-changed-parm-c-v0.c: Source
code for binary test input above.
* tests/data/test-diff-suppr/test9-changed-parm-c-v1.c: Likewise.
* tests/test-diff-suppr.cc (in_out_specs): Add the new test input
data to the vector the test inputs to run this harness over.
* tests/data/Makefile.am: Add the new files to the source
distribution.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
33 files changed:
changelog [deleted file]
include/abg-comparison.h
include/abg-ir.h
src/abg-comparison.cc
src/abg-hash.cc
src/abg-ir.cc
tests/data/Makefile.am
tests/data/test-abicompat/test0-fn-changed-report-0.txt
tests/data/test-diff-dwarf/libtest21-redundant-fn-v0.so [new file with mode: 0755]
tests/data/test-diff-dwarf/libtest21-redundant-fn-v1.so [new file with mode: 0755]
tests/data/test-diff-dwarf/libtest22-changed-parm-c-v0.so [new file with mode: 0755]
tests/data/test-diff-dwarf/libtest22-changed-parm-c-v1.so [new file with mode: 0755]
tests/data/test-diff-dwarf/test21-redundant-fn-report-0.txt [new file with mode: 0644]
tests/data/test-diff-dwarf/test21-redundant-fn-v0.cc [new file with mode: 0644]
tests/data/test-diff-dwarf/test21-redundant-fn-v1.cc [new file with mode: 0644]
tests/data/test-diff-dwarf/test22-changed-parm-c-report-0.txt [new file with mode: 0644]
tests/data/test-diff-dwarf/test22-changed-parm-c-v0.c [new file with mode: 0644]
tests/data/test-diff-dwarf/test22-changed-parm-c-v1.c [new file with mode: 0644]
tests/data/test-diff-suppr/libtest8-redundant-fn-v0.so [new file with mode: 0755]
tests/data/test-diff-suppr/libtest8-redundant-fn-v1.so [new file with mode: 0755]
tests/data/test-diff-suppr/libtest9-changed-parm-c-v0.so [new file with mode: 0755]
tests/data/test-diff-suppr/libtest9-changed-parm-c-v1.so [new file with mode: 0755]
tests/data/test-diff-suppr/test5-fn-suppr-report-0.txt
tests/data/test-diff-suppr/test8-redundant-fn-report-0.txt [new file with mode: 0644]
tests/data/test-diff-suppr/test8-redundant-fn-report-1.txt [new file with mode: 0644]
tests/data/test-diff-suppr/test8-redundant-fn-v0.cc [new file with mode: 0644]
tests/data/test-diff-suppr/test8-redundant-fn-v1.cc [new file with mode: 0644]
tests/data/test-diff-suppr/test9-changed-parm-c-report-0.txt [new file with mode: 0644]
tests/data/test-diff-suppr/test9-changed-parm-c-report-1.txt [new file with mode: 0644]
tests/data/test-diff-suppr/test9-changed-parm-c-v0.c [new file with mode: 0644]
tests/data/test-diff-suppr/test9-changed-parm-c-v1.c [new file with mode: 0644]
tests/test-diff-dwarf.cc
tests/test-diff-suppr.cc

diff --git a/changelog b/changelog
deleted file mode 100644 (file)
index f220b23..0000000
--- a/changelog
+++ /dev/null
@@ -1,156 +0,0 @@
-Implement generic diff tree walking and port categorization over it
-
-       * include/abg-comp-filter.h (apply_filter): Declare new overload
-       that takes a corpus_diff_sptr ...
-       * src/abg-comp-filter.cc (apply_filter): ... and define it.  On
-       the existing overload for diff_sptr, make sure to traverse all
-       diff nodes, even those that have already been traversed.
-       * include/abg-comparison.h (enum diff_category): Remove
-       NOT_REDUNDANT_CATEGORY, add REDUNDANT_CATEGORY.
-       (operator&=, +operator<<): Declare new operators for enum diff_category.
-       (diff_context::{forbid_traversing_a_node_twice,
-       traversing_a_node_twice_is_forbidden):
-       (diff_context::categorizing_redundancy): Remove this declaration.
-       (diff_context::maybe_apply_filters): Declare a new overload that
-       takes a corpus_diff_sptr.  And a take a new flag that says if it
-       should visit all nodes including those that have already been
-       visited.
-       (diff::priv_): Make this data member protected.
-       (diff::{begin_traversing, is_traversing, end_traversing,
-       finish_diff_type, children_nodes, append_child_node,
-       get_pretty_representation, chain_into_hierarchy, traverse}):
-       Declare new member functions.
-       (distinct_diff::{finish_diff_type, get_pretty_representation,
-       chain_into_hierarchy}): Likewise.
-       (distinct_diff::traverse): Remove.
-       (pointer_diff::pointer_diff): Take the underlying type diff in
-       parameter.
-       (pointer_diff::{finish_diff_type, get_pretty_representation,
-       chain_into_hierarchy}): Declare new member functions.
-       (pointer_diff::traverse): Remove.
-       (reference_type_def::reference_type_def): Take the underlying type
-       diff in parameter.
-       ({array_type_def, reference_type_def}::{finish_diff_type,
-       get_pretty_representation, chain_into_hierarchy}): Declare new
-       member functions.
-       ({array_type_diff, reference_type_def}::traverse): Remove.
-       (qualified_type_diff::qualified_type_diff): Take the underlying
-       type diff in parameter.
-       ({enum_diff, qualified_type_diff, class_diff}::{finish_diff_type,
-       get_pretty_representation, chain_into_hierarchy}): Declare new
-       member functions.
-       ({enum_diff, qualified_type_diff, class_diff}::traverse): Remove.
-       (is_class_diff): Declare new function.
-       (base_diff::base_diff): Take the underlying type diff in
-       parameter.
-       ({scope_diff, base_diff}::{finish_diff_type, get_pretty_representation,
-       chain_into_hierarchy}): Declare new member functions.
-       ({scope_diff, base_diff}::traverse): Remove.
-       (function_decl_diff::function_decl_diff): Take the return type
-       diff as parameter.
-       ({function_decl_diff, type_decl_diff}::{finish_diff_type,
-       get_pretty_representation, chain_into_hierarchy}): Declare new
-       member functions.
-       ({function_decl_diff, type_decl_diff}::traverse): Remove.
-       (typedef_diff::typedef_diff): Take the underlying type diff as
-       parameter.
-       (typedef::{finish_diff_type, get_pretty_representation,
-       chain_into_hierarchy}): Declare new member functions.
-       ({typedef, translation_unit_diff}::traverse): Remove member
-       function.
-       (corpus_diff::{finish_diff_type, children_nodes,
-       append_child_node, changed_variables, get_pretty_representation,
-       chain_into_hierarchy}): Declare new member functions.
-       (class diff_node_visitor::{visit_begin, visit_end}): Declare new
-       member functions.
-       (propagate_categories, print_diff_tree, categorizing_redundancy)
-       (clear_redundancy_categorization, apply_filters): New functions
-       and function overloads.
-       * src/abg-comparison.cc (TRY_PRE_VISIT, TRY_PRE_VISIT_CLASS_DIFF)
-       (TRY_POST_VISIT, TRY_POST_VISIT_CLASS_DIFF)
-       (CATEGORIZE_REDUNDANCY_FROM_CHILD_NODE)
-       (UPDATE_REDUNDANCY_CATEGORIZATION_FROM_NODE_SUBTREE)
-       (TRAVERSE_DIFF_NODE_AND_PROPAGATE_CATEGORY)
-       (TRAVERSE_MEM_DIFF_NODE_AND_PROPAGATE_CATEGORY)
-       (TRAVERSE_MEM_FN_DIFF_NODE_AND_PROPAGATE_CATEGORY)
-       (ENSURE_DIFF_NODE_TRAVERSED_ONCE)
-       (ENSURE_MEM_DIFF_NODE_TRAVERSED_ONCE): Remove these macros.
-       Hurrah.
-       (diff_context::priv::categorizing_redundancy_): Remove.
-       (diff_context::priv::forbid_traversing_a_node_twice_): Add new
-       data member.
-       (diff_context::priv::priv): Adjust.
-       (diff_context::{forbid_traversing_a_node_twice,
-       traversing_a_node_twice_is_forbidden}): Define new member
-       functions.
-       (diff_context::maybe_apply_filters): Once filters are applied (and
-       categories are set to the relevant diff tree nodes, run a pass
-       over the diff tree to propagate the categories to the relevant
-       diff tree parent nodes.  Add an overload for corpus_diff_sptr.
-       (diff_context::categorizing_redundancy): Remove member function.
-       (diff_context::maybe_apply_filters): Define a new overload for
-       corpus_diff_sptr
-       (struct diff::priv::{finished_, traversing_, children_,
-       pretty_representation_}):  New data members.
-       (diff::priv::priv): Adjust.
-       (diff::{begin_traversing, is_traversing, end_traversing,
-       finish_diff_type, children_nodes, append_child_node, traverse,
-       set_category, get_pretty_representation, chain_into_hierarchy}):
-       Define new member functions.
-       (diff::is_filtered_out): Do not refer to NOT_REDUNDANT_CATEGORY
-       anymore.  Rather, use the new REDUNDANT_CATEGORY.
-       ({distinct_diff, var_diff, pointer_diff, array_diff,
-       reference_diff, qualified_type_diff, enum_diff, class_diff,
-       base_diff, scope_diff, function_decl_diff, type_decl_diff,
-       typedef_diff}::{get_pretty_representation, chain_into_hierarchy,
-       finish_diff_type}): Define new member functions.
-       ({distinct_diff, var_diff, pointer_diff, array_diff,
-       reference_diff, qualified_type_diff, enum_diff, class_diff,
-       base_diff, scope_diff, function_decl_diff, type_decl_diff,
-       typedef_diff, translation_unit_diff}::traverse): Remove member
-       functions.
-       (operator&=, operator<<): Define new operators for diff_category.
-       ({function_decl_diff, typedef_diff}::priv::priv): Add a new
-       constructor.
-       (pointer_diff::{priv::priv, pointer_diff})
-       (reference_diff::{priv::priv, reference_diff})
-       (qualified_type_diff::{priv::priv, qualified_type_diff})
-       (enum_diff::{priv::priv, enum_diff}, base_diff::{priv::priv,
-       base_diff}, function_decl_diff::function_decl_diff): Take the
-       underlying type diff in parameter.
-       (compute_diff): Adjust the pointer_diff, reference_diff,
-       qualified_type_diff, base_diff, function_decl_diff overloads.
-       (class_diff::priv::{count_filtered_bases,
-       count_filtered_subtype_changed_dm, count_filtered_changed_dm,
-       count_filtered_changed_mem_fns, count_filtered_inserted_mem_fns,
-       count_filtered_deleted_mem_fns}): Adjust for the call to
-       diff_context::maybe_apply_filters.
-       (corpus_diff::priv::{finished_, pretty_representation_}): New data
-       member.
-       (corpus_diff::priv::priv): New constructor.
-       (corpus_diff::priv::clear_redundancy_categorization): Define new
-       member function.
-       (corpus_diff::priv::apply_filters_and_compute_diff_stats):
-       Adjust for call to diff_context::maybe_apply_filters.  Also, call
-       clear_redundancy_categorization at the end.
-       (corpus_diff::priv::categorize_redundant_changed_sub_nodes):
-       Revisit logic.
-       (corpus_diff::{chain_into_hierarchy, finish_diff_type,
-       children_nodes, append_child_node, changed_variables,
-       get_pretty_representation}): Define new member functions.
-       (corpus_diff::report): Categorize redundancy for every top level
-       function/variable diff.
-       (corpus_diff::traverse): Adjust to the new traversing interface.
-       (diff_node_visitor::{visit_begin, visit_end}): Define new member
-       functions.
-       (struct category_propagation_visitor, struct diff_node_printer)
-       (struct redundancy_marking_visitor, struct
-       redundancy_clearing_visitor): New diff tree node visitors.
-       (propagate_categories, print_diff_tree, categorize_redundancy)
-       (clear_redundancy_categorization, apply_filters): Define new
-       functions.
-       * tests/Makefile.am: Add the new tests/print-diff-tree.cc to the
-       source distribution.  Build it into a tests/printdifftree binary.
-       * tools/abidiff.cc (print_diff_tree): Add debugging functions to
-       call from within the debugger.  By default, this function and its
-       overloads are not compiled.
index 6ed33cad7f6d12706265da23c3cea2aa6700ee44..694cfddf0b888cd315a3bce3e0321db8d87486ed 100644 (file)
@@ -62,6 +62,32 @@ class diff;
 /// Convenience typedef for a shared_ptr for the @ref diff class
 typedef shared_ptr<diff> diff_sptr;
 
+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;
+
+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;
+
+class base_diff;
+
+/// Convenience typedef for a shared pointer to a @ref base_diff type.
+typedef shared_ptr<base_diff> base_diff_sptr;
+
+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 a boolean.
 typedef unordered_map<size_t, bool> pointer_map;
@@ -81,12 +107,8 @@ typedef pair<decl_base_sptr, decl_base_sptr> changed_type_or_decl;
 /// 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 pair of class_decl::base_spec_sptr.
-typedef pair<class_decl::base_spec_sptr,
-            class_decl::base_spec_sptr> changed_base;
-
-/// Convenience typedef for a map of string and changed_base.
-typedef unordered_map<string, changed_base> string_changed_base_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 changed function parameter.  The first element of
 /// the pair is the old function parm and the second element is the
@@ -96,11 +118,12 @@ typedef pair<function_decl::parameter_sptr,
 
 /// 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, changed_parm> string_changed_parm_map;
+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, changed_parm> unsigned_changed_parm_map;
+typedef unordered_map<unsigned, fn_parm_diff_sptr>
+unsigned_fn_parm_diff_sptr_map;
 
 /// Convenience typedef for a vector of changed_parm.
 typedef vector<changed_parm> changed_parms_type;
@@ -115,11 +138,20 @@ typedef unordered_map<unsigned,
 typedef unordered_map<string,
                      changed_type_or_decl> string_changed_type_or_decl_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;
+
 /// Convience typedef for a map which value is a changed type or decl.
 /// The key of the map is an unsigned integer.
 typedef unordered_map<unsigned,
                      changed_type_or_decl> unsigned_changed_type_or_decl_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 tyepdef for a vector of changed type or decl.
 typedef vector<changed_type_or_decl> changed_type_or_decl_vector;
 
@@ -147,16 +179,10 @@ typedef unordered_map<string, changed_enumerator> string_changed_enumerator_map;
 /// value is a pointer to @ref decl_base.
 typedef unordered_map<string, function_decl*> string_function_ptr_map;
 
-/// Convenience typedef for a pair of pointer to @ref function_decl
-/// representing a @ref function_decl change.  The first
-/// member of the pair represents the initial function and the second
-/// member represents the changed function.
-typedef std::pair<function_decl*, function_decl*> changed_function_ptr;
-
 /// Convenience typedef for a map which key is a string and which
-/// value is a @ref changed_function_ptr.
+/// value is a @ref function_decl_diff_sptr.
 typedef unordered_map<string,
-                     changed_function_ptr> string_changed_function_ptr_map;
+                     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
@@ -189,9 +215,9 @@ typedef std::pair<var_decl*, var_decl*> changed_var_ptr;
 /// 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 stirng and which
-/// value is a @ref changed_var_ptr.
-typedef unordered_map<string, changed_var_ptr> string_changed_var_ptr_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;
 
@@ -695,19 +721,6 @@ class diff_context
   struct priv;
   shared_ptr<priv> priv_;
 
-public:
-  diff_context();
-
-  void
-  set_corpora(const corpus_sptr corp1,
-             const corpus_sptr corp2);
-
-  const corpus_sptr
-  get_first_corpus() const;
-
-  const corpus_sptr
-  get_second_corpus() const;
-
   diff_sptr
   has_diff_for(const decl_base_sptr first,
               const decl_base_sptr second) const;
@@ -733,6 +746,39 @@ public:
   void
   add_diff(const diff* d);
 
+  void
+  set_canonical_diff_for(const decl_base_sptr first,
+                        const decl_base_sptr second,
+                        const diff_sptr);
+
+  diff_sptr
+  set_or_get_canonical_diff_for(const decl_base_sptr first,
+                               const decl_base_sptr second,
+                               const diff_sptr canonical_diff);
+
+public:
+  diff_context();
+
+  void
+  set_corpora(const corpus_sptr corp1,
+             const corpus_sptr corp2);
+
+  const corpus_sptr
+  get_first_corpus() const;
+
+  const corpus_sptr
+  get_second_corpus() const;
+
+  diff_sptr
+  get_canonical_diff_for(const decl_base_sptr first,
+                        const decl_base_sptr second) const;
+
+  diff_sptr
+  get_canonical_diff_for(const diff_sptr d) const;
+
+  void
+  initialize_canonical_diff(const diff_sptr diff);
+
   bool
   diff_has_been_traversed(const diff*) const;
 
@@ -771,11 +817,11 @@ public:
 
   void
   maybe_apply_filters(diff_sptr diff,
-                     bool traverse_nodes_once = true);
+                     bool traverse_nodes_once = false);
 
   void
   maybe_apply_filters(corpus_diff_sptr diff,
-                     bool traverse_nodes_once = true);
+                     bool traverse_nodes_once = false);
 
   suppressions_type&
   suppressions() const;
@@ -857,13 +903,25 @@ public:
 
   void
   show_added_symbols_unreferenced_by_debug_info(bool f);
+
+  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.
+///
+/// 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;
+
   struct priv;
   typedef shared_ptr<priv> priv_sptr;
 
@@ -894,6 +952,9 @@ protected:
   virtual void
   finish_diff_type();
 
+  void
+  set_canonical_diff(diff *);
+
 public:
   decl_base_sptr
   first_subject() const;
@@ -901,11 +962,13 @@ public:
   decl_base_sptr
   second_subject() const;
 
-  const vector<diff*>&
+  const vector<diff_sptr>&
   children_nodes() const;
 
+  diff* get_canonical_diff() const;
+
   void
-  append_child_node(diff*);
+  append_child_node(diff_sptr);
 
   const diff_context_sptr
   context() const;
@@ -1108,11 +1171,6 @@ compute_diff_for_distinct_kinds(const decl_base_sptr,
                                const decl_base_sptr,
                                diff_context_sptr ctxt);
 
-class var_diff;
-
-/// Convenience typedef for a shared pointer to var_diff.
-typedef shared_ptr<var_diff> var_diff_sptr;
-
 /// Abstracts a diff between two instances of @ref var_decl
 class var_diff : public decl_diff_base
 {
@@ -1473,12 +1531,6 @@ compute_diff(const enum_type_decl_sptr,
             const enum_type_decl_sptr,
             diff_context_sptr);
 
-class class_diff;
-
-/// Convenience typedef for a shared pointer on a @ref class_diff type.
-typedef shared_ptr<class_diff> class_diff_sptr;
-
-
 /// This type abstracts changes for a class_decl.
 class class_diff : public type_diff_base
 {
@@ -1505,10 +1557,12 @@ protected:
 public:
   //TODO: add change of the name of the type.
 
-  shared_ptr<class_decl>
+  virtual ~class_diff();
+
+  class_decl_sptr
   first_class_decl() const;
 
-  shared_ptr<class_decl>
+  class_decl_sptr
   second_class_decl() const;
 
   const edit_script&
@@ -1523,7 +1577,7 @@ public:
   const string_base_sptr_map&
   inserted_bases() const;
 
-  const string_changed_base_map&
+  const string_base_diff_sptr_map&
   changed_bases();
 
   const edit_script&
@@ -1597,11 +1651,6 @@ compute_diff(const class_decl_sptr       first,
             const class_decl_sptr      second,
             diff_context_sptr          ctxt);
 
-class base_diff;
-
-/// Convenience typedef for a shared pointer to base_diff.
-typedef shared_ptr<base_diff> base_diff_sptr;
-
 /// An abstraction of a diff between two instances of class_decl::base_spec.
 class base_diff : public diff
 {
@@ -1766,10 +1815,56 @@ compute_diff(const scope_decl_sptr first_scope,
             const scope_decl_sptr second_scope,
             diff_context_sptr ctxt);
 
-class function_decl_diff;
+/// Abstraction of a diff between two function parameters.
+class fn_parm_diff : public decl_diff_base
+{
+  struct priv;
+  typedef shared_ptr<priv> priv_sptr;
 
-/// Convenience typedef for a shared pointer on a @ref function_decl type.
-typedef shared_ptr<function_decl_diff> function_decl_diff_sptr;
+  priv_sptr priv_;
+
+  virtual void
+  finish_diff_type();
+
+  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
+  get_type_diff() const;
+
+  virtual const string&
+  get_pretty_representation() const;
+
+  virtual unsigned
+  length() const;
+
+  virtual bool
+  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);
 
 /// Abstraction of a diff between two function_decl.
 class function_decl_diff : public decl_diff_base
@@ -1796,6 +1891,7 @@ protected:
   finish_diff_type();
 
 public:
+
 friend function_decl_diff_sptr
 compute_diff(const function_decl_sptr  first,
             const function_decl_sptr   second,
@@ -1810,7 +1906,7 @@ compute_diff(const function_decl_sptr     first,
   const diff_sptr
   return_type_diff() const;
 
-  const string_changed_parm_map&
+  const string_fn_parm_diff_sptr_map&
   subtype_changed_parms() const;
 
   const string_parm_map&
@@ -2020,11 +2116,11 @@ public:
   corpus_sptr
   second_corpus() const;
 
-  const vector<diff*>&
-  chidren_nodes() const;
+  const vector<diff_sptr>&
+  children_nodes() const;
 
   void
-  append_child_node(diff*);
+  append_child_node(diff_sptr);
 
   edit_script&
   function_changes() const;
@@ -2041,7 +2137,7 @@ public:
   const string_function_ptr_map&
   added_functions();
 
-  const string_changed_function_ptr_map&
+  const string_function_decl_diff_sptr_map&
   changed_functions();
 
   const string_var_ptr_map&
@@ -2050,7 +2146,7 @@ public:
   const string_var_ptr_map&
   added_variables() const;
 
-  const string_changed_var_ptr_map&
+  const string_var_diff_sptr_map&
   changed_variables();
 
   const string_elf_symbol_map&
index e3b07e269bbca2665fabf45c95af52db1f4abceb..abf8d69ad3921e0c79e38151e067b95f30a1352f 100644 (file)
 /// This file contains the declarations of the Internal Representation
 /// of libabigail.
 
-/*!
-
-@defgroup Memory Memory management considerations
-@{
-
-For memory management and garbage collection of libabigail's IR
-artifacts, we use std::tr1::shared_ptr and std::tr1::weak_ptr.
-
-When manipulating these IR artifacts, there are a few rules to keep in
-mind.
-
-<b>The declaration for a type is owned by only one scope </b>
-
-This means that for each instance of abigail::type_base (a type) there
-is an instance of abigail::scope_decl that owns a @ref
-abigail::decl_base_sptr (a shared pointer to an abigail::decl_base)
-that points to the declaration of that type.  The
-abigail::type_base_sptr is added to the scope using the function
-abigail::add_decl_to_scope().
-
-There is a kind of type that is usually not syntactically owned by a
-scope: it's function type.  In libabigail function types are
-represented by abigail::function_type and abigail::method_type.  These
-types must be owned by the translation unit they originate from.
-Adding them to the translation unit must be done by a call to the
-method function abigail::translation::get_canonical_function_type().
-The type returned by that function is the one to use.
-
-<b> A declaration that has a type does NOT own the type </b>
-
-This means that, for instance, in an abigail::var_decl (a variable
-declaration), the type of the declaration is not owned by the
-declaration.  In other (concrete) words, the variable declaration
-doesn't have a shared pointer to the type.  Rather, it has a *weak*
-pointer to its type.  That means that it has a data member of type
-abigail::type_base_wptr that contains the type of the declaration.
-
-But then abigail::var_decl::get_type() returns a shared pointer that
-is constructed from the internal weak pointer to the type.  That way,
-users of the type of the var can own a temporary reference on it and
-be assured that the type's life time is long enough for their need.
-
-Likewise, data members, function and template parameters similarly
-have weak pointers on their type.
-
-@}
+/// @defgroup Memory Memory management
+/// @{
+///
+/// How objects' lifetime is handled in libabigail.
+///
+/// For memory management and garbage collection of libabigail's IR
+/// artifacts, we use std::tr1::shared_ptr and std::tr1::weak_ptr.
+///
+/// When manipulating these IR artifacts, there are a few rules to keep in
+/// mind.
+///
+/// <b>The declaration for a type is owned by only one scope </b>
+///
+/// This means that for each instance of abigail::type_base (a type) there
+/// is an instance of abigail::scope_decl that owns a @ref
+/// abigail::decl_base_sptr (a shared pointer to an abigail::decl_base)
+/// that points to the declaration of that type.  The
+/// abigail::type_base_sptr is added to the scope using the function
+/// abigail::add_decl_to_scope().
+///
+/// There is a kind of type that is usually not syntactically owned by a
+/// scope: it's function type.  In libabigail function types are
+/// represented by abigail::function_type and abigail::method_type.  These
+/// types must be owned by the translation unit they originate from.
+/// Adding them to the translation unit must be done by a call to the
+/// method function abigail::translation::get_canonical_function_type().
+/// The type returned by that function is the one to use.
+///
+/// <b> A declaration that has a type does NOT own the type </b>
+///
+/// This means that, for instance, in an abigail::var_decl (a variable
+/// declaration), the type of the declaration is not owned by the
+/// declaration.  In other (concrete) words, the variable declaration
+/// doesn't have a shared pointer to the type.  Rather, it has a *weak*
+/// pointer to its type.  That means that it has a data member of type
+/// abigail::type_base_wptr that contains the type of the declaration.
+///
+/// But then abigail::var_decl::get_type() returns a shared pointer that
+/// is constructed from the internal weak pointer to the type.  That way,
+/// users of the type of the var can own a temporary reference on it and
+/// be assured that the type's life time is long enough for their need.
+///
+/// Likewise, data members, function and template parameters similarly
+/// have weak pointers on their type.
+///
+/// @}
 
-*/
 namespace abigail
 {
 
@@ -690,6 +689,12 @@ public:
   virtual size_t
   get_hash() const;
 
+  virtual string
+  get_pretty_representation() const;
+
+  virtual void
+  get_qualified_name(string& qualified_name) const;
+
   void
   set_hash(size_t) const;
 
@@ -708,15 +713,9 @@ public:
   const string&
   get_name() const;
 
-  virtual string
-  get_pretty_representation() const;
-
   string
   get_qualified_parent_name() const;
 
-  virtual void
-  get_qualified_name(string& qualified_name) const;
-
   string
   get_qualified_name() const;
 
@@ -1726,153 +1725,7 @@ public:
   typedef std::vector<parameter_sptr> parameters;
 
   /// Abtraction for the parameter of a function.
-  class parameter
-  {
-    type_base_wptr     type_;
-    unsigned           index_;
-    bool               variadic_marker_;
-    std::string        name_;
-    location           location_;
-    bool               artificial_;
-
-  public:
-
-    /// Hasher for an instance of function::parameter
-    struct hash;
-
-    parameter(const shared_ptr<type_base> type,
-             unsigned index,
-             const std::string& name,
-             location loc, bool variadic_marker = false)
-      : type_(type), index_(index), variadic_marker_ (variadic_marker),
-       name_(name), location_(loc),
-       artificial_(false)
-    {}
-
-    parameter(const shared_ptr<type_base> type,
-             unsigned index,
-             const std::string& name,
-             location loc, bool variadic_marker,
-             bool is_artificial)
-      : type_(type), index_(index), variadic_marker_ (variadic_marker),
-       name_(name), location_(loc),
-       artificial_(is_artificial)
-    {}
-
-    parameter(const shared_ptr<type_base> type,
-             const std::string& name,
-             location loc, bool variadic_marker = false,
-             bool is_artificial = false)
-      : type_(type), index_(0), variadic_marker_ (variadic_marker),
-       name_(name), location_(loc), artificial_(is_artificial)
-    {}
-
-    parameter(const shared_ptr<type_base> type,
-             unsigned index = 0,
-             bool variadic_marker = false)
-    : type_(type),
-      index_(index),
-      variadic_marker_ (variadic_marker),
-      artificial_(false)
-    {}
-
-    const type_base_sptr
-    get_type()const
-    {
-      if (type_.expired())
-       return type_base_sptr();
-      return type_base_sptr(type_);
-    }
-
-    /// @return a copy of the type name of the parameter.
-    const string
-    get_type_name() const
-    {
-      string str;
-      if (variadic_marker_)
-       str = "...";
-      else
-       {
-         type_base_sptr t = get_type();
-         assert(t);
-         str += abigail::ir::get_type_name(t);
-       }
-      return str;
-    }
-
-    /// @return a copy of the pretty representation of the type of the
-    /// parameter.
-    const string
-    get_type_pretty_representation() const
-    {
-      string str;
-      if (variadic_marker_)
-       str = "...";
-      else
-       {
-         type_base_sptr t = get_type();
-         assert(t);
-         str += get_type_declaration(t)->get_pretty_representation();
-       }
-      return str;
-    }
-
-    const string
-    get_name_id() const;
-
-    unsigned
-    get_index() const
-    {return index_;}
-
-    void
-    set_index(unsigned i)
-    {index_ = i;}
-
-    const std::string&
-    get_name() const
-    {return name_;}
-
-    location
-    get_location() const
-    {return location_;}
-
-    /// Test if the parameter is artificial.
-    ///
-    /// Being artificial means the parameter was not explicitely
-    /// mentionned in the source code, but was rather artificially
-    /// created by the compiler.
-    ///
-    /// @return true if the parameter is artificial, false otherwise.
-    bool
-    get_artificial() const
-    {return artificial_;}
-
-    /// Getter for the artificial-ness of the parameter.
-    ///
-    /// Being artificial means the parameter was not explicitely
-    /// mentionned in the source code, but was rather artificially
-    /// created by the compiler.
-    ///
-    /// @param f set to true if the parameter is artificial.
-    void
-    set_artificial(bool f)
-    {artificial_ = f;}
-
-    bool
-    operator==(const parameter& o) const
-    {
-      if ((get_variadic_marker() != o.get_variadic_marker())
-         || (get_index() != o.get_index())
-         || (!!get_type() != !!o.get_type())
-         || (get_type() && (*get_type() != *o.get_type())))
-       return false;
-      return true;
-    }
-
-    bool
-    get_variadic_marker() const
-    {return variadic_marker_;}
-  };
+  class parameter;
 
   function_decl(const std::string& name,
                function_type_sptr function_type,
@@ -1952,6 +1805,103 @@ public:
   virtual ~function_decl();
 }; // end class function_decl
 
+bool
+equals(const function_decl::parameter&,
+       const function_decl::parameter&,
+       change_kind&);
+
+/// Abstraction of a function parameter.
+class function_decl::parameter : public decl_base
+{
+  struct priv;
+  typedef shared_ptr<priv> priv_sptr;
+
+  priv_sptr priv_;
+
+public:
+
+  /// Hasher for an instance of function::parameter
+  struct hash;
+
+  parameter(const type_base_sptr       type,
+           unsigned                    index,
+           const std::string&          name,
+           location                    loc,
+           bool                        variadic_marker = false);
+
+  parameter(const type_base_sptr       type,
+           unsigned                    index,
+           const std::string&          name,
+           location                    loc,
+           bool                        variadic_marker,
+           bool                        is_artificial);
+
+  parameter(const type_base_sptr       type,
+           const std::string&          name,
+           location                    loc,
+           bool                        variadic_marker = false,
+           bool                        is_artificial   = false);
+
+  parameter(const type_base_sptr       type,
+           unsigned                    index = 0,
+           bool                        variadic_marker = false);
+
+  const type_base_sptr
+  get_type()const;
+
+  const string
+  get_type_name() const;
+
+  const string
+  get_type_pretty_representation() const;
+
+  const string
+  get_name_id() const;
+
+  unsigned
+  get_index() const;
+
+  void
+  set_index(unsigned i);
+
+   bool
+  get_artificial() const;
+
+  void
+  set_artificial(bool f);
+
+  bool
+  get_variadic_marker() const;
+
+  bool
+  operator==(const parameter& o) const;
+
+  virtual bool
+  operator==(const decl_base&) const;
+
+  virtual bool
+  traverse(ir_node_visitor& v);
+
+  virtual size_t
+  get_hash() const;
+
+  virtual void
+  get_qualified_name(string& qualified_name) const;
+}; // end class function_decl::parameter
+
+/// A hashing functor for a function_decl::parameter.
+struct function_decl::parameter::hash
+{
+  size_t
+  operator()(const function_decl::parameter&) const;
+
+  size_t
+  operator()(const function_decl::parameter*) const;
+
+  size_t
+  operator()(const function_decl::parameter_sptr) const;
+}; // end struct function_decl::parameter::hash
+
 bool
 equals(const function_type&, const function_type&, change_kind&);
 
@@ -3208,6 +3158,7 @@ struct ir_node_visitor : public node_visitor_base
   virtual bool visit(typedef_decl*);
   virtual bool visit(var_decl*);
   virtual bool visit(function_decl*);
+  virtual bool visit(function_decl::parameter*);
   virtual bool visit(function_tdecl*);
   virtual bool visit(class_tdecl*);
   virtual bool visit(class_decl*);
index eee6cd2bc32665b30831305c6b13b726cc2c471b..3bb824fcef7e65bdb8313df5c394b92cd2c0b7f8 100644 (file)
@@ -40,6 +40,78 @@ namespace abigail
 namespace comparison
 {
 
+///
+///
+///@defgroup DiffNode Internal Representation of the comparison engine
+/// @{
+///
+/// How changes are represented in libabigail's comparison engine.
+///
+///@par diff nodes
+///
+/// The internal representation of the comparison engine is basically
+/// a graph of @ref instances of @ref diff node.  We refer to these
+/// just as <em>diff nodes</em>.  A diff node represents a change
+/// between two ABI artifacts represented by instances of types of the
+/// abigail::ir namespace.  These two artifacts that are being
+/// compared are called the <em>subjects of the diff</em>.
+///
+/// The types of that IR are in the abigail::comparison namespace.
+///
+///@par comparing diff nodes
+///
+/// Comparing two instances of @ref diff nodes amounts to comparing
+/// the subject of the diff.  In other words, two @ref diff nodes are
+/// equal if and only if their subjects are equal.  Thus, two @ref
+/// diff nodes can have different memory addresses and yet be equal.
+///
+///@par diff reporting and context
+///
+/// A diff node can be serialized to an output stream to express, in
+/// a human-readable textual form, the different changes that exist
+/// between its two subjects.  This is done by invoking the
+/// diff::report() method.  That reporting is controlled by several
+/// parameters that are conceptually part of the context of the diff.
+/// That context is materialized by an instance of the @ref
+/// diff_context type.
+///
+/// Please note that the role of the instance(s) of @ref diff_context
+/// is boreader than just controlling the reporting of @ref diff
+/// nodes.  Basically, a @ref diff node itself is created following
+/// behaviours that are controlled by a particular instance of
+/// diff_context.  A diff node is created in a particular diff
+/// context, so to speak.
+///
+/// @}
+///
+
+///
+/// @defgroup CanonicalDiff Canonical diff tree nodes
+/// @{
+///
+/// @par Equivalence of @ref diff nodes
+///
+/// Each @ref diff node has a property named <em>Canonical Diff
+/// Node</em>.  If \c D is a diff node, the canonical diff node of @c
+/// D, noted @c C(D) is a particular diff node that is equal to @c D.
+/// Thus, a fast way to compare two @ref diff node is to perform a
+/// pointer comparison of their canonical diff nodes.
+///
+/// A set of equivalent @ref diff nodes is a set of diff nodes that
+/// all have the same canonical node.  All the nodes of that set are
+/// equal.
+///
+/// A canonical node is registereded for a given diff node by invoking
+/// the method diff_context::initialize_canonical_diff().
+///
+/// Please note that the diff_context holds all the canonical diffs
+/// that got registered through it.  Thus, the life time of all of
+/// canonical diff objects is the same as the life time of the @ref
+/// diff_context they relate to.
+///
+/// @}
+///
+
 // Inject types from outside in here.
 using std::vector;
 using std::tr1::dynamic_pointer_cast;
@@ -101,7 +173,7 @@ operator~(visiting_kind l)
 /// @param S2 the second diff subject to take in account.
 #define RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER(S1, S2) \
   do {                                                                 \
-    if (diff_sptr _diff_ = context()->has_diff_for(S1, S2))            \
+    if (diff_sptr _diff_ = context()->get_canonical_diff_for(S1, S2))  \
       if (_diff_->currently_reporting() || _diff_->reported_once())    \
        {                                                               \
          if (_diff_->currently_reporting())                            \
@@ -126,7 +198,7 @@ operator~(visiting_kind l)
 /// diagnostic.
 #define RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER2(D, INTRO_TEXT) \
   do {                                                                 \
-    if (diff_sptr _diff_ = context()->has_diff_for(D))                 \
+    if (diff_sptr _diff_ = context()->get_canonical_diff_for(D))       \
       if (_diff_->currently_reporting() || _diff_->reported_once())    \
        {                                                               \
          string _name_ = _diff_->first_subject()->get_pretty_representation(); \
@@ -151,7 +223,7 @@ operator~(visiting_kind l)
 /// diagnostic.
 #define RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER3(S1, S2, INTRO_TEXT) \
     do {                                                               \
-      if (diff_sptr _diff_ = context()->has_diff_for(S1, S2))          \
+      if (diff_sptr _diff_ = context()->get_canonical_diff_for(S1, S2)) \
        if (_diff_->currently_reporting() || _diff_->reported_once())   \
          {                                                             \
            string _name_ = _diff_->first_subject()->get_pretty_representation(); \
@@ -2187,6 +2259,7 @@ struct diff_context::priv
 {
   diff_category                        allowed_category_;
   decls_diff_map_type                  decls_diff_map;
+  vector<diff_sptr>                    canonical_diffs;
   vector<filtering::filter_base_sptr>  filters_;
   suppressions_type                    suppressions_;
   pointer_map                          traversed_diff_nodes_;
@@ -2398,15 +2471,118 @@ diff_context::add_diff(const diff_sptr d)
       add_diff(d->first_subject(), d->second_subject(), d);
 }
 
+/// Getter for the @ref CanonicalDiff "canonical diff node" for the
+/// @ref diff represented by their two subjects.
+///
+/// @param first the first subject of the diff.
+///
+/// @param second the second subject of the diff.
+///
+/// @return the canonical diff for the diff node represented by the
+/// two diff subjects @p first and @p second.  If no canonical diff
+/// node was registered for these subjects, then a nil node is
+/// returned.
+diff_sptr
+diff_context::get_canonical_diff_for(const decl_base_sptr first,
+                                    const decl_base_sptr second) const
+{return has_diff_for(first, second);}
+
+/// Getter for the @ref CanonicalDiff "canonical diff node" for the
+/// @ref diff represented by the two subjects of a given diff node.
+///
+/// @param d the diff node to get the canonical node for.
+///
+/// @return the canonical diff for the diff node represented by the
+/// two diff subjects of @p d.  If no canonical diff node was
+/// registered for these subjects, then a nil node is returned.
+diff_sptr
+diff_context::get_canonical_diff_for(const diff_sptr d) const
+{return has_diff_for(d);}
+
+/// Setter for the @ref CanonicalDiff "canonical diff node" for the
+/// @ref diff represented by their two subjects.
+///
+/// @param first the first subject of the diff.
+///
+/// @param second the second subject of the diff.
+///
+/// @param d the new canonical diff.
+void
+diff_context::set_canonical_diff_for(const decl_base_sptr first,
+                                    const decl_base_sptr second,
+                                    const diff_sptr d)
+{
+  assert(d);
+  if (!has_diff_for(first, second))
+    {
+      add_diff(first, second, d);
+      priv_->canonical_diffs.push_back(d);
+    }
+}
+
+/// If there is is a @ref CanonicalDiff "canonical diff node"
+/// registered for two diff subjects, return it.  Otherwise, register
+/// a canonical diff node for these two diff subjects and return it.
+///
+/// @param first the first subject of the diff.
+///
+/// @param second the second subject of the diff.
+///
+/// @param d the new canonical diff node.
+///
+/// @returnt the canonical diff node.
+diff_sptr
+diff_context::set_or_get_canonical_diff_for(const decl_base_sptr first,
+                                           const decl_base_sptr second,
+                                           const diff_sptr canonical_diff)
+{
+  assert(canonical_diff);
+
+  diff_sptr canonical = get_canonical_diff_for(first, second);
+  if (!canonical)
+    {
+      canonical = canonical_diff;
+      set_canonical_diff_for(first, second, canonical);
+    }
+  return canonical;
+}
+
+/// Set the canonical diff node property of a given diff node
+/// appropriately.
+///
+/// For a given diff node that has no canonical diff node, retrieve
+/// the canonical diff node (by looking at its diff subjects and at
+/// the current context) and set the canonical diff node property of
+/// the diff node to that canonical diff node.  If no canonical diff
+/// node has been registered to the diff context for the subjects of
+/// the diff node then, register the canonical diff node as being the
+/// diff node itself; and set its canonical diff node property as
+/// such.  Otherwise, if the diff node already has a canonical diff
+/// node, do nothing.
+///
+/// @param diff the diff node to initialize the canonical diff node
+/// property for.
+void
+diff_context::initialize_canonical_diff(const diff_sptr diff)
+{
+  if (diff->get_canonical_diff() == 0)
+    {
+      diff_sptr canonical =
+       set_or_get_canonical_diff_for(diff->first_subject(),
+                                     diff->second_subject(),
+                                     diff);
+      diff->set_canonical_diff(canonical.get());
+    }
+}
+
 /// Test if a diff node has been traversed.
 ///
 /// @param d the diff node to consider.
 bool
 diff_context::diff_has_been_traversed(const diff* d) const
 {
-  const diff* canonical = has_diff_for(d);
-  if (!canonical)
-    canonical = d;
+  const diff* canonical = d->get_canonical_diff();
+  assert(canonical);
 
   size_t ptr_value = reinterpret_cast<size_t>(canonical);
   return (priv_->traversed_diff_nodes_.find(ptr_value)
@@ -2422,17 +2598,16 @@ diff_context::diff_has_been_traversed(const diff_sptr d) const
 
 /// Mark a diff node as traversed by a traversing algorithm.
 ///
+/// Actually, it's the @ref CanonicalDiff "canonical diff" of this
+/// node that is marked as traversed.
+///
 /// Subsequent invocations of diff_has_been_traversed() on the diff
 /// node will yield true.
 void
 diff_context::mark_diff_as_traversed(const diff* d)
 {
-   const diff* canonical = has_diff_for(d);
-   if (!canonical)
-     {
-       add_diff(d);
-       canonical = d;
-     }
+  const diff* canonical = d->get_canonical_diff();
+  assert(canonical);
 
    size_t ptr_value = reinterpret_cast<size_t>(canonical);
    priv_->traversed_diff_nodes_[ptr_value] = true;
@@ -2741,7 +2916,8 @@ struct diff::priv
   bool                 traversing_;
   decl_base_sptr       first_subject_;
   decl_base_sptr       second_subject_;
-  vector<diff*>        children_;
+  vector<diff_sptr>    children_;
+  diff*                canonical_diff_;
   diff_context_sptr    ctxt_;
   diff_category        category_;
   mutable bool         reported_once_;
@@ -2758,17 +2934,16 @@ public:
        diff_category category,
        bool reported_once,
        bool currently_reporting)
-    : finished_(false),
-      traversing_(false),
+    : finished_(),
+      traversing_(),
       first_subject_(first_subject),
       second_subject_(second_subject),
+      canonical_diff_(),
       ctxt_(ctxt),
       category_(category),
       reported_once_(reported_once),
       currently_reporting_(currently_reporting)
   {}
-
-  friend class diff;
 };// end class diff::priv
 
 /// Constructor for the @ref diff type.
@@ -2816,25 +2991,35 @@ diff::diff(decl_base_sptr       first_subject,
 /// given node as being traversed (or not), so that
 /// diff::is_traversing() can tell if the node is being traversed.
 ///
+/// The canonical node is marked as being traversed too.
+///
 /// These functions are called by the traversing code.
 void
 diff::begin_traversing()
 {
   assert(!is_traversing());
+  if (priv_->canonical_diff_)
+    priv_->canonical_diff_->priv_->traversing_ = true;
   priv_->traversing_ = true;
 }
 
 /// Tell if a given node is being traversed or not.
 ///
+/// It's the canonical node which is looked at, actually.
+///
 /// Please read the comments for the diff::begin_traversing() for mode
 /// context.
 ///
 /// @return true if the current instance of @diff is being traversed.
 bool
 diff::is_traversing() const
-{return priv_->traversing_;}
+{
+  if (priv_->canonical_diff_)
+    return priv_->canonical_diff_->priv_->traversing_;
+  return priv_->traversing_;
+}
 
-/// Flag a given diff node as not being traversed.
+/// Flag a given diff node as not being traversed anymore.
 ///
 /// Please read the comments of the function diff::begin_traversing()
 /// for mode context;
@@ -2842,7 +3027,13 @@ void
 diff::end_traversing()
 {
   assert(is_traversing());
+  if (priv_->canonical_diff_)
+    priv_->canonical_diff_->priv_->traversing_ = false;
   priv_->traversing_ = false;
+
+  // Make this node as having been traversed, to allow the detection
+  // of nodes that might have been visited more than once.
+  context()->mark_diff_as_traversed(this);
 }
 
 /// Finish the building of a given kind of a diff tree node.
@@ -2873,16 +3064,37 @@ diff::second_subject() const
 /// Getter fo the children nodes of the the current @ref diff node.
 ///
 /// @return a vector of the children nodes.
-const vector<diff*>&
+const vector<diff_sptr>&
 diff::children_nodes() const
 {return priv_->children_;}
 
+/// Getter for the canonical diff of the current instance of @ref
+/// diff.
+///
+/// Note that the canonical diff node for the current instanc eof diff
+/// node must have been set by invoking
+/// class_diff::initialize_canonical_diff() on the current instance of
+/// diff node.
+///
+/// @return the canonical diff node or null if none was set.
+diff*
+diff::get_canonical_diff() const
+{return priv_->canonical_diff_;}
+
+/// Setter for the canonical diff of the current instance of @ref
+/// diff.
+///
+/// @param d the new canonical node to set.
+void
+diff::set_canonical_diff(diff * d)
+{priv_->canonical_diff_ = d;}
+
 /// Add a new child node to the vector of children nodes for the
 /// current @ref diff node.
 ///
 /// @param d the new child node to add to the children nodes.
 void
-diff::append_child_node(diff* d)
+diff::append_child_node(diff_sptr d)
 {
   assert(d);
   priv_->children_.push_back(d);
@@ -2909,7 +3121,11 @@ diff::context(diff_context_sptr c)
 /// current diff, false otherwise.
 bool
 diff::currently_reporting() const
-{return priv_->currently_reporting_;}
+{
+  if (priv_->canonical_diff_)
+    return priv_->canonical_diff_->priv_->currently_reporting_;
+  return priv_->currently_reporting_;
+}
 
 /// Sets a flag saying if we are currently in the middle of emitting
 /// a report for this diff.
@@ -2918,7 +3134,11 @@ diff::currently_reporting() const
 /// current diff, false otherwise.
 void
 diff::currently_reporting(bool f) const
-{priv_->currently_reporting_ = f;}
+{
+  if (priv_->canonical_diff_)
+    priv_->canonical_diff_->priv_->currently_reporting_ = f;
+  priv_->currently_reporting_ = f;
+}
 
 /// Tests if a report has already been emitted for the current diff.
 ///
@@ -2926,7 +3146,10 @@ diff::currently_reporting(bool f) const
 /// current diff, false otherwise.
 bool
 diff::reported_once() const
-{return priv_->reported_once_;}
+{
+  assert(priv_->canonical_diff_);
+  return priv_->canonical_diff_->priv_->reported_once_;
+}
 
 /// The generic traversing code that walks a given diff sub-tree.
 ///
@@ -2954,12 +3177,11 @@ diff::traverse(diff_node_visitor& v)
     {
       v.visit_end(this);
       end_traversing();
-      context()->mark_diff_as_traversed(this);
       return false;
     }
 
   if (!(v.get_visiting_kind() & SKIP_CHILDREN_VISITING_KIND))
-    for (vector<diff*>::const_iterator i = children_nodes().begin();
+    for (vector<diff_sptr>::const_iterator i = children_nodes().begin();
         i != children_nodes().end();
         ++i)
       {
@@ -2967,7 +3189,6 @@ diff::traverse(diff_node_visitor& v)
          {
            v.visit_end(this);
            end_traversing();
-           context()->mark_diff_as_traversed(this);
            return false;
          }
       }
@@ -2976,13 +3197,11 @@ diff::traverse(diff_node_visitor& v)
     {
       v.visit_end(this);
       end_traversing();
-      context()->mark_diff_as_traversed(this);
       return false;
     }
 
   v.visit_end(this);
   end_traversing();
-  context()->mark_diff_as_traversed(this);
 
   return true;
 }
@@ -2993,7 +3212,11 @@ diff::traverse(diff_node_visitor& v)
 /// current diff, false otherwise.
 void
 diff::reported_once(bool f) const
-{priv_->reported_once_ = f;}
+{
+  assert(priv_->canonical_diff_);
+  priv_->canonical_diff_->priv_->reported_once_ = f;
+  priv_->reported_once_ = f;
+}
 
 /// Getter for the category of the current diff tree node.
 ///
@@ -3221,15 +3444,15 @@ distinct_diff::get_pretty_representation() const
 /// Populate the vector of children node of the @ref diff base type
 /// sub-object of this instance of @distinct_diff.
 ///
-/// The children node can then later be retrieved using
-/// diff::children_node().
+/// The children nodes can then later be retrieved using
+/// diff::children_nodes().
 void
 distinct_diff::chain_into_hierarchy()
 {
   assert(entities_are_of_distinct_kinds(first(), second()));
 
   if (diff_sptr d = compatible_child_diff())
-    append_child_node(d.get());
+    append_child_node(d);
 }
 
 /// Constructor for @ref distinct_diff.
@@ -3413,15 +3636,10 @@ compute_diff_for_distinct_kinds(const decl_base_sptr first,
   if (!distinct_diff::entities_are_of_distinct_kinds(first, second))
     return distinct_diff_sptr();
 
-  if (diff_sptr dif = ctxt->has_diff_for(first, second))
-    {
-      distinct_diff_sptr d = dynamic_pointer_cast<distinct_diff>(dif);
-      assert(d);
-      return d;
-    }
   distinct_diff_sptr result(new distinct_diff(first, second, ctxt));
 
-  ctxt->add_diff(first, second, result);
+  ctxt->initialize_canonical_diff(result);
+
   return result;
 }
 
@@ -3726,13 +3944,7 @@ compute_diff_for_types(const type_base_sptr first,
   decl_base_sptr f = dynamic_pointer_cast<decl_base>(first);
   decl_base_sptr s = dynamic_pointer_cast<decl_base>(second);
 
-  if (d = ctxt->has_diff_for(f, s))
-    ;
-  else
-    {
-      d = compute_diff_for_types(f, s, ctxt);
-      ctxt->add_diff(f, s, d);
-    }
+  d = compute_diff_for_types(f, s, ctxt);
 
   return d;
 }
@@ -3937,12 +4149,10 @@ represent_data_member(var_decl_sptr d, ostream& out)
        << " (in bits)\n";
 }
 
-/// Represent the changes that happened on two versions of a given
-/// class data member.
-///
-/// @param o the older version of the data member.
+/// Represent the changes carried by an instance of @ref var_diff that
+/// represent a difference between two class data members.
 ///
-/// @param n the newer version of the data member.
+/// @param diff diff the diff node to represent.
 ///
 /// @param ctxt the diff context to use.
 ///
@@ -3950,16 +4160,17 @@ represent_data_member(var_decl_sptr d, ostream& out)
 ///
 /// @param indent the indentation string to use for the change report.
 static void
-represent(var_decl_sptr        o,
-         var_decl_sptr n,
+represent(var_diff_sptr        diff,
          diff_context_sptr     ctxt,
          ostream&              out,
          const string& indent = "")
 {
-  diff_sptr diff = compute_diff_for_decls(o, n, ctxt);
   if (!diff->to_be_reported())
     return;
 
+  var_decl_sptr o = diff->first_var();
+  var_decl_sptr n = diff->second_var();
+
   bool emitted = false;
   string name1 = o->get_qualified_name();
   string name2 = n->get_qualified_name();
@@ -4056,11 +4267,8 @@ represent(var_decl_sptr  o,
        out << "now becomes static";
       emitted = true;
     }
-  if (*o->get_type() != *n->get_type())
+  if (diff_sptr d = diff->type_diff())
     {
-      diff_sptr d = compute_diff_for_types(o->get_type(),
-                                          n->get_type(),
-                                          ctxt);
       if (d->to_be_reported())
        {
          if (!emitted)
@@ -4265,13 +4473,13 @@ struct var_diff::priv
 };//end struct var_diff
 
 /// Populate the vector of children node of the @ref diff base type
-/// sub-object of this instance of @var_diff.
+/// sub-object of this instance of @ref var_diff.
 ///
 /// The children node can then later be retrieved using
 /// diff::children_node().
 void
 var_diff::chain_into_hierarchy()
-{append_child_node(type_diff().get());}
+{append_child_node(type_diff());}
 
 /// @return the pretty representation for this current instance of
 /// @ref var_diff.
@@ -4340,7 +4548,13 @@ var_diff::second_var() const
 /// @return the diff of the types of the instances of @ref var_decl.
 diff_sptr
 var_diff::type_diff() const
-{return priv_->type_diff_;}
+{
+  if (!priv_->type_diff_)
+    priv_->type_diff_ = compute_diff(first_var()->get_type(),
+                                    second_var()->get_type(),
+                                    context());
+  return priv_->type_diff_;
+}
 
 /// Compute and return the length of the current diff.
 ///
@@ -4386,6 +4600,7 @@ var_diff::report(ostream& out, const string& indent) const
     {
       if (d->to_be_reported())
        {
+         RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER2(d, "type");
          out << indent << "type of variable changed:\n";
          d->report(out, indent + " ");
        }
@@ -4406,19 +4621,8 @@ compute_diff(const var_decl_sptr first,
             const var_decl_sptr        second,
             diff_context_sptr          ctxt)
 {
-  if (diff_sptr di = ctxt->has_diff_for(first, second))
-    {
-      var_diff_sptr d = dynamic_pointer_cast<var_diff>(di);
-      assert(d);
-      return d;
-    }
-
-  diff_sptr type_diff = compute_diff(first->get_type(),
-                                    second->get_type(),
-                                    ctxt);
-  var_diff_sptr d(new var_diff(first, second, type_diff, ctxt));
-  ctxt->add_diff(first, second, d);
-
+  var_diff_sptr d(new var_diff(first, second, diff_sptr(), ctxt));
+  ctxt->initialize_canonical_diff(d);
   return d;
 }
 
@@ -4494,7 +4698,7 @@ struct pointer_diff::priv
 /// diff::children_node().
 void
 pointer_diff::chain_into_hierarchy()
-{append_child_node(underlying_type_diff().get());}
+{append_child_node(underlying_type_diff());}
 
 /// Constructor for a pointer_diff.
 ///
@@ -4630,18 +4834,12 @@ compute_diff(pointer_type_def_sptr      first,
             pointer_type_def_sptr      second,
             diff_context_sptr          ctxt)
 {
-  if (diff_sptr dif = ctxt->has_diff_for(first, second))
-    {
-      pointer_diff_sptr d = dynamic_pointer_cast<pointer_diff>(dif);
-      assert(d);
-      return d;
-    }
 
   diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
                                       second->get_pointed_to_type(),
                                       ctxt);
   pointer_diff_sptr result(new pointer_diff(first, second, d, ctxt));
-  ctxt->add_diff(first, second, result);
+  ctxt->initialize_canonical_diff(result);
 
   return result;
 }
@@ -4666,7 +4864,7 @@ struct array_diff::priv
 /// diff::children_node().
 void
 array_diff::chain_into_hierarchy()
-{append_child_node(element_type_diff().get());}
+{append_child_node(element_type_diff());}
 
 /// Constructor for array_diff
 ///
@@ -4893,18 +5091,11 @@ compute_diff(array_type_def_sptr        first,
             array_type_def_sptr        second,
             diff_context_sptr          ctxt)
 {
-  if (diff_sptr dif = ctxt->has_diff_for(first, second))
-    {
-      array_diff_sptr d = dynamic_pointer_cast<array_diff>(dif);
-      return d;
-    }
-
   diff_sptr d = compute_diff_for_types(first->get_element_type(),
                                       second->get_element_type(),
                                       ctxt);
   array_diff_sptr result(new array_diff(first, second, d, ctxt));
-  ctxt->add_diff(first, second, result);
-
+  ctxt->initialize_canonical_diff(result);
   return result;
 }
 // </array_type_def>
@@ -4925,7 +5116,7 @@ struct reference_diff::priv
 /// diff::children_node().
 void
 reference_diff::chain_into_hierarchy()
-{append_child_node(underlying_type_diff().get());}
+{append_child_node(underlying_type_diff());}
 
 /// Constructor for reference_diff
 ///
@@ -5057,20 +5248,12 @@ compute_diff(reference_type_def_sptr    first,
             reference_type_def_sptr    second,
             diff_context_sptr          ctxt)
 {
-  if (diff_sptr dif = ctxt->has_diff_for(first, second))
-    {
-      reference_diff_sptr d = dynamic_pointer_cast<reference_diff>(dif);
-      return d;
-    }
-
   diff_sptr d = compute_diff_for_types(first->get_pointed_to_type(),
                                       second->get_pointed_to_type(),
                                       ctxt);
   reference_diff_sptr result(new reference_diff(first, second, d, ctxt));
-  ctxt->add_diff(first, second, result);
-
+  ctxt->initialize_canonical_diff(result);
   return result;
-
 }
 // </reference_type_def>
 
@@ -5091,7 +5274,7 @@ struct qualified_type_diff::priv
 /// diff::children_node().
 void
 qualified_type_diff::chain_into_hierarchy()
-{append_child_node(underlying_type_diff().get());}
+{append_child_node(underlying_type_diff());}
 
 /// Constructor for qualified_type_diff.
 ///
@@ -5276,21 +5459,12 @@ compute_diff(const qualified_type_def_sptr      first,
             const qualified_type_def_sptr      second,
             diff_context_sptr                  ctxt)
 {
-  if (diff_sptr dif = ctxt->has_diff_for(first, second))
-    {
-      qualified_type_diff_sptr d =
-       dynamic_pointer_cast<qualified_type_diff>(dif);
-      assert(d);
-      return d;
-    }
-
   diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
                                       second->get_underlying_type(),
                                       ctxt);
   qualified_type_diff_sptr result(new qualified_type_diff(first, second,
                                                          d, ctxt));
-  ctxt->add_diff(first, second, result);
-
+  ctxt->initialize_canonical_diff(result);
   return result;
 }
 
@@ -5395,7 +5569,7 @@ enum_diff::ensure_lookup_tables_populated()
 /// diff::children_node().
 void
 enum_diff::chain_into_hierarchy()
-{append_child_node(underlying_type_diff().get());}
+{append_child_node(underlying_type_diff());}
 
 /// Constructor for enum_diff.
 ///
@@ -5660,13 +5834,6 @@ compute_diff(const enum_type_decl_sptr first,
             const enum_type_decl_sptr second,
             diff_context_sptr ctxt)
 {
-  if (diff_sptr dif = ctxt->has_diff_for(first, second))
-    {
-      enum_diff_sptr d = dynamic_pointer_cast<enum_diff>(dif);
-      assert(d);
-      return d;
-    }
-
   diff_sptr ud = compute_diff_for_types(first->get_underlying_type(),
                                        second->get_underlying_type(),
                                        ctxt);
@@ -5680,7 +5847,7 @@ compute_diff(const enum_type_decl_sptr first,
 
   d->ensure_lookup_tables_populated();
 
-  ctxt->add_diff(first, second, d);
+  ctxt->initialize_canonical_diff(d);
 
   return d;
 }
@@ -5699,7 +5866,7 @@ struct class_diff::priv
 
   string_base_sptr_map deleted_bases_;
   string_base_sptr_map inserted_bases_;
-  string_changed_base_map changed_bases_;
+  string_base_diff_sptr_map changed_bases_;
   string_decl_base_sptr_map deleted_member_types_;
   string_decl_base_sptr_map inserted_member_types_;
   string_changed_type_or_decl_map changed_member_types_;
@@ -5708,13 +5875,13 @@ struct class_diff::priv
   string_decl_base_sptr_map inserted_data_members_;
   unsigned_decl_base_sptr_map inserted_dm_by_offset_;
   // This map contains the data member which sub-type changed.
-  string_changed_type_or_decl_map subtype_changed_dm_;
+  string_var_diff_sptr_map subtype_changed_dm_;
   // This one contains the list of data members changes that can be
   // represented as a data member foo that got removed from offset N,
   // and a data member bar that got inserted at offset N; IOW, this
   // can be translated as data member foo that got changed into data
   // member bar at offset N.
-  unsigned_changed_type_or_decl_map changed_dm_;
+  unsigned_var_diff_sptr_map changed_dm_;
   string_member_function_sptr_map deleted_member_functions_;
   string_member_function_sptr_map inserted_member_functions_;
   string_changed_member_function_sptr_map changed_member_functions_;
@@ -5735,13 +5902,13 @@ struct class_diff::priv
   member_class_tmpl_has_changed(decl_base_sptr) const;
 
   size_t
-  count_filtered_bases(const diff_context_sptr&);
+  count_filtered_bases();
 
   size_t
-  count_filtered_subtype_changed_dm(const diff_context_sptr&);
+  count_filtered_subtype_changed_dm();
 
   size_t
-  count_filtered_changed_dm(const diff_context_sptr&);
+  count_filtered_changed_dm();
 
   size_t
   count_filtered_changed_mem_fns(const diff_context_sptr&);
@@ -5848,7 +6015,7 @@ class_diff::ensure_lookup_tables_populated(void) const
              {
                if (j->second != b)
                  priv_->changed_bases_[qname] =
-                   std::make_pair(j->second, b);
+                   compute_diff(j->second, b, context());
                priv_->deleted_bases_.erase(j);
              }
            else
@@ -5931,7 +6098,8 @@ class_diff::ensure_lookup_tables_populated(void) const
          {
            unsigned i = *iit;
            decl_base_sptr d = second_class_decl()->get_data_members()[i];
-           string qname = d->get_qualified_name();
+           var_decl_sptr dm = dynamic_pointer_cast<var_decl>(d);
+           string qname = dm->get_qualified_name();
            assert(priv_->inserted_data_members_.find(qname)
                   == priv_->inserted_data_members_.end());
            string_decl_base_sptr_map::const_iterator j =
@@ -5939,8 +6107,12 @@ class_diff::ensure_lookup_tables_populated(void) const
            if (j != priv_->deleted_data_members_.end())
              {
                if (*j->second != *d)
-                 priv_->subtype_changed_dm_[qname]=
-                   std::make_pair(j->second, d);
+                 {
+                   var_decl_sptr old_dm =
+                     dynamic_pointer_cast<var_decl>(j->second);
+                   priv_->subtype_changed_dm_[qname]=
+                     compute_diff(old_dm, dm, context());
+                 }
                priv_->deleted_data_members_.erase(j);
              }
            else
@@ -5977,10 +6149,15 @@ class_diff::ensure_lookup_tables_populated(void) const
        unsigned_decl_base_sptr_map::const_iterator j =
          priv_->deleted_dm_by_offset_.find(i->first);
        if (j != priv_->deleted_dm_by_offset_.end())
-         priv_->changed_dm_[i->first] = std::make_pair(j->second, i->second);
+         {
+           var_decl_sptr old_dm = dynamic_pointer_cast<var_decl>(j->second);
+           var_decl_sptr new_dm = dynamic_pointer_cast<var_decl>(i->second);
+           priv_->changed_dm_[i->first] =
+             compute_diff(old_dm, new_dm, context());
+         }
       }
 
-    for (unsigned_changed_type_or_decl_map::const_iterator i =
+    for (unsigned_var_diff_sptr_map::const_iterator i =
           priv_->changed_dm_.begin();
         i != priv_->changed_dm_.end();
         ++i)
@@ -5988,9 +6165,9 @@ class_diff::ensure_lookup_tables_populated(void) const
        priv_->deleted_dm_by_offset_.erase(i->first);
        priv_->inserted_dm_by_offset_.erase(i->first);
        priv_->deleted_data_members_.erase
-         (i->second.first->get_qualified_name());
+         (i->second->first_var()->get_qualified_name());
        priv_->inserted_data_members_.erase
-         (i->second.second->get_qualified_name());
+         (i->second->second_var()->get_qualified_name());
       }
   }
 
@@ -6166,12 +6343,12 @@ class_decl::base_spec_sptr
 class_diff::priv::base_has_changed(class_decl::base_spec_sptr d) const
 {
   string qname = d->get_base_class()->get_qualified_name();
-  string_changed_base_map::const_iterator it =
+  string_base_diff_sptr_map::const_iterator it =
     changed_bases_.find(qname);
 
   return (it == changed_bases_.end())
     ? class_decl::base_spec_sptr()
-    : it->second.second;
+    : it->second->second_base();
 
 }
 
@@ -6203,12 +6380,12 @@ decl_base_sptr
 class_diff::priv::subtype_changed_dm(decl_base_sptr d) const
 {
   string qname = d->get_qualified_name();
-  string_changed_type_or_decl_map::const_iterator it =
+  string_var_diff_sptr_map::const_iterator it =
     subtype_changed_dm_.find(qname);
 
-  return ((it == subtype_changed_dm_.end())
-         ? decl_base_sptr()
-         : it->second.second);
+  if (it == subtype_changed_dm_.end())
+    return decl_base_sptr();
+  return it->second->second_var();
 }
 
 /// Test whether a given member class template has changed.
@@ -6231,25 +6408,17 @@ class_diff::priv::member_class_tmpl_has_changed(decl_base_sptr d) const
 
 /// Count the number of bases classes whose changes got filtered out.
 ///
-/// @param ctxt the context to use to determine the filtering settings
-/// from the user.
-///
 /// @return the number of bases classes whose changes got filtered
 /// out.
 size_t
-class_diff::priv::count_filtered_bases(const diff_context_sptr& ctxt)
+class_diff::priv::count_filtered_bases()
 {
   size_t num_filtered = 0;
-  for (string_changed_base_map::const_iterator i = changed_bases_.begin();
+  for (string_base_diff_sptr_map::const_iterator i = changed_bases_.begin();
        i != changed_bases_.end();
        ++i)
     {
-      class_decl::base_spec_sptr o =
-       dynamic_pointer_cast<class_decl::base_spec>(i->second.first);
-      class_decl::base_spec_sptr n =
-       dynamic_pointer_cast<class_decl::base_spec>(i->second.second);
-      diff_sptr diff = compute_diff(o, n, ctxt);
-      ctxt->maybe_apply_filters(diff, /*traverse_nodes_once=*/false);
+      diff_sptr diff = i->second;
       if (diff->is_filtered_out())
        ++num_filtered;
     }
@@ -6263,21 +6432,15 @@ class_diff::priv::count_filtered_bases(const diff_context_sptr& ctxt)
 ///
 /// @return the number of data members whose changes got filtered out.
 size_t
-class_diff::priv::count_filtered_subtype_changed_dm(const diff_context_sptr& ctxt)
+class_diff::priv::count_filtered_subtype_changed_dm()
 {
   size_t num_filtered= 0;
-  for (string_changed_type_or_decl_map::const_iterator i =
+  for (string_var_diff_sptr_map::const_iterator i =
         subtype_changed_dm_.begin();
        i != subtype_changed_dm_.end();
        ++i)
     {
-      var_decl_sptr o =
-       dynamic_pointer_cast<var_decl>(i->second.first);
-      var_decl_sptr n =
-       dynamic_pointer_cast<var_decl>(i->second.second);
-      diff_sptr diff = compute_diff_for_decls(o, n, ctxt);
-      ctxt->maybe_apply_filters(diff, /*traverse_nodes_once=*/false);
-      if (diff->is_filtered_out())
+      if (i->second->is_filtered_out())
        ++num_filtered;
     }
   return num_filtered;
@@ -6285,23 +6448,17 @@ class_diff::priv::count_filtered_subtype_changed_dm(const diff_context_sptr& ctx
 
 /// Count the number of data member offsets that have changed.
 ///
-/// @param ctxt the diff context to use.
+/// @return the number of filtered changed data members.
 size_t
-class_diff::priv::count_filtered_changed_dm(const diff_context_sptr& ctxt)
+class_diff::priv::count_filtered_changed_dm()
 {
   size_t num_filtered= 0;
 
-  for (unsigned_changed_type_or_decl_map::const_iterator i =
-        changed_dm_.begin();
+  for (unsigned_var_diff_sptr_map::const_iterator i = changed_dm_.begin();
        i != changed_dm_.end();
        ++i)
     {
-      var_decl_sptr o =
-       dynamic_pointer_cast<var_decl>(i->second.first);
-      var_decl_sptr n =
-       dynamic_pointer_cast<var_decl>(i->second.second);
-      diff_sptr diff = compute_diff(o, n, ctxt);
-      ctxt->maybe_apply_filters(diff, /*traverse_nodes_once=*/false);
+      diff_sptr diff = i->second;
       if (diff->is_filtered_out())
        ++num_filtered;
     }
@@ -6355,7 +6512,7 @@ class_diff::priv::count_filtered_changed_mem_fns(const diff_context_sptr& ctxt)
       SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED;
 
       diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
-      ctxt->maybe_apply_filters(diff, /*traverse_nodes_once=*/false);
+      ctxt->maybe_apply_filters(diff);
 
       if (diff->is_filtered_out())
        ++count;
@@ -6389,7 +6546,7 @@ class_diff::priv::count_filtered_inserted_mem_fns(const diff_context_sptr& ctxt)
       SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED;
 
       diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
-      ctxt->maybe_apply_filters(diff, /*traverse_nodes_once=*/false);
+      ctxt->maybe_apply_filters(diff);
 
       if (diff->get_category() != NO_CHANGE_CATEGORY
          && diff->is_filtered_out())
@@ -6424,7 +6581,7 @@ class_diff::priv::count_filtered_deleted_mem_fns(const diff_context_sptr& ctxt)
       SKIP_MEM_FN_IF_VIRTUALITY_DISALLOWED;
 
       diff_sptr diff = compute_diff_for_decls(f, s, ctxt);
-      ctxt->maybe_apply_filters(diff, /*traverse_nodes_once=*/false);
+      ctxt->maybe_apply_filters(diff);
 
       if (diff->get_category() != NO_CHANGE_CATEGORY
          && diff->is_filtered_out())
@@ -6443,33 +6600,27 @@ void
 class_diff::chain_into_hierarchy()
 {
   // base class changes.
-  for (string_changed_base_map::const_iterator i =
+  for (string_base_diff_sptr_map::const_iterator i =
         priv_->changed_bases_.begin();
        i != priv_->changed_bases_.end();
        ++i)
-    if (diff_sptr d = compute_diff(i->second.first,
-                                  i->second.second,
-                                  context()))
-      append_child_node(d.get());
+    if (diff_sptr d = i->second)
+      append_child_node(d);
 
   // data member changes
-  for (string_changed_type_or_decl_map::const_iterator i =
+  for (string_var_diff_sptr_map::const_iterator i =
         priv_->subtype_changed_dm_.begin();
        i != priv_->subtype_changed_dm_.end();
        ++i)
-    if (diff_sptr d = compute_diff_for_decls(i->second.first,
-                                            i->second.second,
-                                            context()))
-      append_child_node(d.get());
+    if (diff_sptr d = i->second)
+      append_child_node(d);
 
-  for (unsigned_changed_type_or_decl_map::const_iterator i =
+  for (unsigned_var_diff_sptr_map::const_iterator i =
         priv_->changed_dm_.begin();
        i != priv_->changed_dm_.end();
        ++i)
-    if (diff_sptr d = compute_diff_for_decls(i->second.first,
-                                            i->second.second,
-                                            context()))
-      append_child_node(d.get());
+    if (diff_sptr d = i->second)
+      append_child_node(d);
 
   // member types changes
   for (string_changed_type_or_decl_map::const_iterator i =
@@ -6479,7 +6630,7 @@ class_diff::chain_into_hierarchy()
     if (diff_sptr d = compute_diff_for_types(i->second.first,
                                             i->second.second,
                                             context()))
-      append_child_node(d.get());
+      append_child_node(d);
 
   // member function changes
   for (string_changed_member_function_sptr_map::const_iterator i =
@@ -6489,7 +6640,7 @@ class_diff::chain_into_hierarchy()
     if (diff_sptr d = compute_diff_for_decls(i->second.first,
                                             i->second.second,
                                             context()))
-      append_child_node(d.get());
+      append_child_node(d);
 }
 
 /// Constructor of class_diff
@@ -6506,6 +6657,9 @@ class_diff::class_diff(shared_ptr<class_decl>     first_scope,
     priv_(new priv)
 {}
 
+class_diff::~class_diff()
+{}
+
 /// Finish building the current instance of @ref class_diff.
 void
 class_diff::finish_diff_type()
@@ -6588,7 +6742,7 @@ class_diff::inserted_bases() const
 ///
 /// @return a map containing the changed base classes, keyed with
 /// their pretty representation.
-const string_changed_base_map&
+const string_base_diff_sptr_map&
 class_diff::changed_bases()
 {return priv_->changed_bases_;}
 
@@ -6617,10 +6771,16 @@ edit_script&
 class_diff::data_members_changes()
 {return priv_->data_members_changes_;}
 
+/// Getter for the data members that got inserted.
+///
+/// @return a map of data members that got inserted.
 const string_decl_base_sptr_map&
 class_diff::inserted_data_members() const
 {return priv_->inserted_data_members_;}
 
+/// Getter for the data members that got deleted.
+///
+/// @return a map of data members that got deleted.
 const string_decl_base_sptr_map&
 class_diff::deleted_data_members() const
 {return priv_->deleted_data_members_;}
@@ -6631,6 +6791,10 @@ const edit_script&
 class_diff::member_fns_changes() const
 {return priv_->member_fns_changes_;}
 
+/// Getter for the members functions that have had a change in a
+/// sub-type, without having a change in their symbol name.
+///
+/// @return a map of member functions that have a sub-type change.
 const string_changed_member_function_sptr_map&
 class_diff::changed_member_fns() const
 {return priv_->changed_member_functions_;}
@@ -6675,66 +6839,65 @@ edit_script&
 class_diff::member_class_tmpls_changes()
 {return priv_->member_class_tmpls_changes_;}
 
-/// A comparison functor to compare two changed data members based on
-/// the offset of their initial value.
-struct changed_data_member_comp
+/// A comparison functor to compare two instances of @ref var_diff
+/// that represent changed data members based on the offset of their
+/// initial value.
+struct var_diff_comp
 {
-  /// @param f the first changed data member to take into account
+  /// @param f the first change to data member to take into account
   ///
-  /// @param s the second changed data member to take into account.
+  /// @param s the second change to data member to take into account.
   ///
   /// @return true iff f is before s.
   bool
-  operator()(const changed_type_or_decl& f,
-            const changed_type_or_decl& s) const
+  operator()(const var_diff_sptr f,
+            const var_diff_sptr s) const
   {
-    var_decl_sptr first_dm = is_data_member(f.first);
-    var_decl_sptr second_dm = is_data_member(s.first);
+    var_decl_sptr first_dm = f->first_var();
+    var_decl_sptr second_dm = s->first_var();
 
-    assert(first_dm);
-    assert(second_dm);
+    assert(is_data_member(first_dm));
+    assert(is_data_member(second_dm));
 
     return get_data_member_offset(first_dm) < get_data_member_offset(second_dm);
   }
-}; // end struct changed_data_member_comp
+}; // end struct var_diff_comp
 
-/// Sort two changed data members by the offset of their initial
-/// value.
+/// Sort the values of a unsigned_var_diff_sptr_map map and store the
+/// result into a vector of var_diff_sptr.
 ///
-/// @param data_members the map of changed data members to sort.
+/// @param map the map of changed data members to sort.
 ///
-/// @param sorted the resulting vector of sorted changed data members.
+/// @param sorted the resulting vector of sorted var_diff_sptr.
 static void
-sort_changed_data_members(const unsigned_changed_type_or_decl_map data_members,
-                         changed_type_or_decl_vector& sorted)
+sort_var_diffs(const unsigned_var_diff_sptr_map map,
+              vector<var_diff_sptr>& sorted)
 {
-  sorted.reserve(data_members.size());
-  for (unsigned_changed_type_or_decl_map::const_iterator i =
-        data_members.begin();
-       i != data_members.end();
+  sorted.reserve(map.size());
+  for (unsigned_var_diff_sptr_map::const_iterator i = map.begin();
+       i != map.end();
        ++i)
     sorted.push_back(i->second);
-  changed_data_member_comp comp;
+  var_diff_comp comp;
   std::sort(sorted.begin(), sorted.end(), comp);
 }
 
-/// Sort a map of changed data members by the offset of their initial
-/// value.
+/// Sort the values of a string_var_diff_sptr_map and store the result
+/// in a vector of var_diff_sptr.
 ///
-/// @param data_members the map of changed data members to sort.
+/// @param map the map of changed data members to sort.
 ///
-/// @param sorted the resulting vector of sorted changed data members.
+/// @param sorted the resulting vector of var_diff_sptr.
 static void
-sort_changed_data_members(const string_changed_type_or_decl_map& data_members,
-                         changed_type_or_decl_vector& sorted)
+sort_var_diffs(const string_var_diff_sptr_map& map,
+              vector<var_diff_sptr>& sorted)
 {
-  sorted.reserve(data_members.size());
-  for (string_changed_type_or_decl_map::const_iterator i =
-        data_members.begin();
-       i != data_members.end();
+  sorted.reserve(map.size());
+  for (string_var_diff_sptr_map::const_iterator i = map.begin();
+       i != map.end();
        ++i)
     sorted.push_back(i->second);
-  changed_data_member_comp comp;
+  var_diff_comp comp;
   std::sort(sorted.begin(), sorted.end(), comp);
 }
 
@@ -6842,23 +7005,21 @@ class_diff::report(ostream& out, const string& indent) const
 
       // Report changes.
       bool emitted = false;
-      size_t num_filtered = priv_->count_filtered_bases(context());
+      size_t num_filtered = priv_->count_filtered_bases();
       if (numchanges)
        {
          report_mem_header(out, numchanges, num_filtered, change_kind,
                            "base class", indent);
-         for (string_changed_base_map::const_iterator it =
+         for (string_base_diff_sptr_map::const_iterator it =
                 priv_->changed_bases_.begin();
               it != priv_->changed_bases_.end();
               ++it)
            {
-             class_decl::base_spec_sptr o =
-               dynamic_pointer_cast<class_decl::base_spec>(it->second.first);
-             class_decl::base_spec_sptr n =
-               dynamic_pointer_cast<class_decl::base_spec>(it->second.second);
-             diff_sptr diff = compute_diff(o, n, context());
+             base_diff_sptr diff = it->second;
              if (!diff->to_be_reported())
                continue;
+
+             class_decl::base_spec_sptr o = diff->first_base();
              out << indent << "  '"
                  << o->get_base_class()->get_pretty_representation()
                  << "' changed:\n";
@@ -7031,46 +7192,35 @@ class_diff::report(ostream& out, const string& indent) const
 
       // report change
       size_t numchanges = priv_->subtype_changed_dm_.size();
-      size_t num_filtered = priv_->count_filtered_subtype_changed_dm(context());
+      size_t num_filtered = priv_->count_filtered_subtype_changed_dm();
       if (numchanges)
        {
          report_mem_header(out, numchanges, num_filtered,
                            subtype_change_kind, "data member", indent);
-         changed_type_or_decl_vector sorted_dms;
-         sort_changed_data_members(priv_->subtype_changed_dm_, sorted_dms);
-         for (changed_type_or_decl_vector::const_iterator it
-                = sorted_dms.begin();
+         vector<var_diff_sptr> sorted_dms;
+         sort_var_diffs(priv_->subtype_changed_dm_, sorted_dms);
+         for (vector<var_diff_sptr>::const_iterator it = sorted_dms.begin();
               it != sorted_dms.end();
               ++it)
-           {
-             var_decl_sptr o =
-               dynamic_pointer_cast<var_decl>(it->first);
-             var_decl_sptr n =
-               dynamic_pointer_cast<var_decl>(it->second);
-             represent(o, n, context(), out, indent + " ");
-           }
+           represent(*it, context(), out, indent + " ");
          out << "\n";
        }
 
       numchanges = priv_->changed_dm_.size();
-      num_filtered = priv_->count_filtered_changed_dm(context());
+      num_filtered = priv_->count_filtered_changed_dm();
       if (numchanges)
        {
          report_mem_header(out, numchanges, num_filtered,
                            change_kind, "data member", indent);
-         changed_type_or_decl_vector sorted_changed_dms;
-         sort_changed_data_members(priv_->changed_dm_,
-                                   sorted_changed_dms);
-         for (changed_type_or_decl_vector::const_iterator it =
+         vector<var_diff_sptr> sorted_changed_dms;
+         sort_var_diffs(priv_->changed_dm_,
+                        sorted_changed_dms);
+         for (vector<var_diff_sptr>::const_iterator it =
                 sorted_changed_dms.begin();
               it != sorted_changed_dms.end();
               ++it)
            {
-             var_decl_sptr o =
-               dynamic_pointer_cast<var_decl>(it->first);
-             var_decl_sptr n =
-               dynamic_pointer_cast<var_decl>(it->second);
-             represent(o, n, context(), out, indent + " ");
+             represent(*it, context(), out, indent + " ");
            }
          out << "\n";
        }
@@ -7290,13 +7440,6 @@ compute_diff(const class_decl_sptr       first,
   class_decl_sptr f = look_through_decl_only_class(first),
     s = look_through_decl_only_class(second);
 
-   if (diff_sptr dif = ctxt->has_diff_for(first, second))
-    {
-      class_diff_sptr d = dynamic_pointer_cast<class_diff>(dif);
-      assert(d);
-      return d;
-    }
-
   class_diff_sptr changes(new class_diff(f, s, ctxt));
 
   // Compare base specs
@@ -7348,8 +7491,16 @@ compute_diff(const class_decl_sptr       first,
 
   changes->ensure_lookup_tables_populated();
 
-  ctxt->add_diff(first, second, changes);
-  ctxt->add_diff(f, s, changes);
+  ctxt->initialize_canonical_diff(changes);
+  assert(changes->get_canonical_diff());
+  if (!ctxt->get_canonical_diff_for(first, second))
+    {
+      // Either first or second is a decl-only class; let's set the
+      // canonical diff here in that case.
+      diff_sptr canonical_diff = ctxt->get_canonical_diff_for(changes);
+      assert(canonical_diff);
+      ctxt->set_canonical_diff_for(first, second, canonical_diff);
+    }
 
   return changes;
 }
@@ -7373,7 +7524,7 @@ struct base_diff::priv
 /// diff::children_node().
 void
 base_diff::chain_into_hierarchy()
-{append_child_node(get_underlying_class_diff().get());}
+{append_child_node(get_underlying_class_diff());}
 
 /// @param first the first base spec to consider.
 ///
@@ -7531,19 +7682,12 @@ compute_diff(const class_decl::base_spec_sptr   first,
             const class_decl::base_spec_sptr   second,
             diff_context_sptr                  ctxt)
 {
-  if (diff_sptr dif = ctxt->has_diff_for(first, second))
-    {
-      base_diff_sptr d = dynamic_pointer_cast<base_diff>(dif);
-      assert(d);
-      return d;
-    }
-
   class_diff_sptr cl = compute_diff(first->get_base_class(),
                                    second->get_base_class(),
                                    ctxt);
   base_diff_sptr changes(new base_diff(first, second, cl, ctxt));
 
-  ctxt->add_diff(first, second, changes);
+  ctxt->initialize_canonical_diff(changes);
 
   return changes;
 }
@@ -7785,7 +7929,7 @@ scope_diff::chain_into_hierarchy()
     if (diff_sptr d = compute_diff_for_types(i->second.first,
                                             i->second.second,
                                             context()))
-      append_child_node(d.get());
+      append_child_node(d);
 
   for (string_changed_type_or_decl_map::const_iterator i =
         changed_decls().begin();
@@ -7794,7 +7938,7 @@ scope_diff::chain_into_hierarchy()
     if (diff_sptr d = compute_diff_for_decls(i->second.first,
                                             i->second.second,
                                             context()))
-      append_child_node(d.get());
+      append_child_node(d);
 }
 
 /// Constructor for scope_diff
@@ -8203,8 +8347,6 @@ compute_diff(const scope_decl_sptr        first,
   d->ensure_lookup_tables_populated();
   d->context(ctxt);
 
-  ctxt->add_diff(first, second, d);
-
   return d;
 }
 
@@ -8223,18 +8365,187 @@ compute_diff(const scope_decl_sptr     first_scope,
             const scope_decl_sptr      second_scope,
             diff_context_sptr          ctxt)
 {
-  if (diff_sptr dif = ctxt->has_diff_for(first_scope, second_scope))
+  scope_diff_sptr d(new scope_diff(first_scope, second_scope, ctxt));
+  d = compute_diff(first_scope, second_scope, d, ctxt);
+  ctxt->initialize_canonical_diff(d);
+  return d;
+}
+
+//</scope_diff stuff>
+
+// <fn_parm_diff stuff>
+struct fn_parm_diff::priv
+{
+  mutable diff_sptr type_diff;
+}; // end struct fn_parm_diff::priv
+
+/// Constructor for the fn_parm_diff type.
+///
+/// @param first the first subject of the diff.
+///
+/// @param second the second subject of the diff.
+///
+/// @param ctxt the context of the diff.
+fn_parm_diff::fn_parm_diff(const function_decl::parameter_sptr first,
+                          const function_decl::parameter_sptr  second,
+                          diff_context_sptr                    ctxt)
+  : decl_diff_base(first, second, ctxt),
+    priv_(new priv)
+{
+  assert(first->get_index() == second->get_index());
+  priv_->type_diff = compute_diff(first->get_type(),
+                                 second->get_type(),
+                                 ctxt);
+}
+
+/// Finish the building of the current instance of @ref fn_parm_diff.
+void
+fn_parm_diff::finish_diff_type()
+{
+  if (diff::priv_->finished_)
+    return;
+  chain_into_hierarchy();
+  diff::priv_->finished_ = true;
+}
+
+/// Getter for the first subject of this diff node.
+///
+/// @return the first function_decl::parameter_sptr subject of this
+/// diff node.
+const function_decl::parameter_sptr
+fn_parm_diff::first_parameter() const
+{return dynamic_pointer_cast<function_decl::parameter>(first_subject());}
+
+/// Getter for the second subject of this diff node.
+///
+/// @return the second function_decl::parameter_sptr subject of this
+/// diff node.
+const function_decl::parameter_sptr
+fn_parm_diff::second_parameter() const
+{return dynamic_pointer_cast<function_decl::parameter>(second_subject());}
+
+/// Getter for the diff representing the changes on the type of the
+/// function parameter involved in the current instance of @ref
+/// fn_parm_diff.
+///
+/// @return a diff_sptr representing the changes on the type of the
+/// function parameter we are interested in.
+diff_sptr
+fn_parm_diff::get_type_diff() const
+{return priv_->type_diff;}
+
+/// Build and return a textual representation of the current instance
+/// of @ref fn_parm_diff.
+///
+/// @return the string representing the current instance of
+/// fn_parm_diff.
+const string&
+fn_parm_diff::get_pretty_representation() const
+{
+  if (diff::priv_->pretty_representation_.empty())
     {
-      scope_diff_sptr d = dynamic_pointer_cast<scope_diff>(dif);
-      assert(d);
-      return d;
+      std::ostringstream o;
+      o << "function_parameter_diff["
+       << first_subject()->get_pretty_representation()
+       << ", "
+       << second_subject()->get_pretty_representation()
+       << "]";
+      diff::priv_->pretty_representation_ = o.str();
     }
+  return diff::priv_->pretty_representation_;
+}
 
-  scope_diff_sptr d(new scope_diff(first_scope, second_scope, ctxt));
-  return compute_diff(first_scope, second_scope, d, ctxt);
+/// Return 0 iff the current diff node carries *NO* change.
+/// Otherwise, return a non-zero positive number.
+///
+/// @return non-zero iff the current diff node carries a change.
+unsigned
+fn_parm_diff::length() const
+{return *first_parameter() != *second_parameter();}
+
+/// Check if the the current diff node carries a local change.
+///
+/// @return true iff the current diff node carries a local change.
+bool
+fn_parm_diff::has_local_changes() const
+{
+  ir::change_kind k = ir::NO_CHANGE_KIND;
+  if (!equals(*first_parameter(), *second_parameter(), k))
+    return k & LOCAL_CHANGE_KIND;
+  return false;
 }
 
-//</scope_diff stuff>
+/// Emit a textual report about the current fn_parm_diff instance.
+///
+/// @param out the output stream to emit the textual report to.
+///
+/// @param indent the indentation string to use in the report.
+void
+fn_parm_diff::report(ostream& out, const string& indent) const
+{
+  function_decl::parameter_sptr f = first_parameter(), s = second_parameter();
+  string f_name_id = f->get_name_id(), s_name_id = s->get_name_id();
+
+  // either the parameter has a sub-type change (if it's name id
+  // hasn't changed) or it has a compatible change (that, is a change
+  // that changes his name w/o changing the signature of the
+  // function).
+  bool has_sub_type_change = (f_name_id == s_name_id);
+
+  if (to_be_reported())
+    {
+      assert(get_type_diff()->to_be_reported());
+      out << indent
+         << "parameter " << f->get_index()
+         << " of type '"
+         << f->get_type_pretty_representation();
+
+      if (has_sub_type_change)
+       out << "' has sub-type changes:\n";
+      else
+       out << "' changed:\n";
+
+      get_type_diff()->report(out, indent + "  ");
+    }
+}
+
+/// Populate the vector of children nodes of the @ref diff base type
+/// sub-object of this instance of @ref fn_parm_diff.
+///
+/// The children nodes can then later be retrieved using
+/// diff::children_nodes()
+void
+fn_parm_diff::chain_into_hierarchy()
+{
+  if (get_type_diff())
+    append_child_node(get_type_diff());
+}
+
+/// Compute the difference between two function_decl::parameter_sptr;
+/// that is, between two function parameters.  Return a resulting
+/// fn_parm_diff_sptr that represents the changes.
+///
+/// @param first the first subject of the diff.
+///
+/// @param second the second subject of the diff.
+///
+/// @param ctxt the context of the diff.
+///
+/// @return fn_parm_diff_sptr the resulting diff node.
+fn_parm_diff_sptr
+compute_diff(const function_decl::parameter_sptr       first,
+            const function_decl::parameter_sptr        second,
+            diff_context_sptr                          ctxt)
+{
+  if (!first || !second)
+    return fn_parm_diff_sptr();
+
+  fn_parm_diff_sptr result(new fn_parm_diff(first, second, ctxt));
+  ctxt->initialize_canonical_diff(result);
+
+  return result;
+}
+// </fn_parm_diff stuff>
 
 // <function_decl_diff stuff>
 struct function_decl_diff::priv
@@ -8257,12 +8568,18 @@ struct function_decl_diff::priv
   edit_script  fn_flags_changes_;
 
   // useful lookup tables.
-  string_parm_map              deleted_parms_;
-  string_parm_map              added_parms_;
-  string_changed_parm_map      subtype_changed_parms_;
-  unsigned_parm_map            deleted_parms_by_id_;
-  unsigned_parm_map            added_parms_by_id_;
-  unsigned_changed_parm_map    changed_parms_by_id_;
+  string_parm_map                      deleted_parms_;
+  string_parm_map                      added_parms_;
+  // This map contains parameters sub-type changes that don't change
+  // the name of the type of the parameter.
+  string_fn_parm_diff_sptr_map         subtype_changed_parms_;
+  unsigned_parm_map                    deleted_parms_by_id_;
+  unsigned_parm_map                    added_parms_by_id_;
+  // This map contains parameter type changes that actually change the
+  // name of the type of the parameter, but in a compatible way;
+  // otherwise, the mangling of the function would have changed (in
+  // c++ at least).
+  unsigned_fn_parm_diff_sptr_map       changed_parms_by_id_;
 
   priv(diff_sptr return_type_diff)
     : return_type_diff_(return_type_diff)
@@ -8368,7 +8685,7 @@ function_decl_diff::ensure_lookup_tables_populated()
              {
                if (*k->second != *parm)
                  priv_->subtype_changed_parms_[parm_name] =
-                   std::make_pair(k->second, parm);
+                   compute_diff(k->second, parm, context());
                priv_->deleted_parms_.erase(parm_name);
              }
            else
@@ -8382,7 +8699,7 @@ function_decl_diff::ensure_lookup_tables_populated()
                if (*k->second != *parm
                    && (k->second->get_name_id() != parm_name))
                  priv_->changed_parms_by_id_[parm->get_index()] =
-                   std::make_pair(k->second, parm);
+                   compute_diff(k->second, parm, context());
                priv_->added_parms_.erase(parm_name);
                priv_->deleted_parms_.erase(k->second->get_name_id());
                priv_->deleted_parms_by_id_.erase(parm->get_index());
@@ -8403,25 +8720,21 @@ void
 function_decl_diff::chain_into_hierarchy()
 {
   if (diff_sptr d = return_type_diff())
-    append_child_node(d.get());
+    append_child_node(d);
 
-  for (string_changed_parm_map::const_iterator i =
+  for (string_fn_parm_diff_sptr_map::const_iterator i =
         subtype_changed_parms().begin();
        i != subtype_changed_parms().end();
        ++i)
-    if (diff_sptr d = compute_diff_for_types(i->second.first->get_type(),
-                                            i->second.second->get_type(),
-                                            context()))
-      append_child_node(d.get());
+    if (diff_sptr d = i->second)
+      append_child_node(d);
 
-  for (unsigned_changed_parm_map::const_iterator i =
+  for (unsigned_fn_parm_diff_sptr_map::const_iterator i =
         priv_->changed_parms_by_id_.begin();
        i != priv_->changed_parms_by_id_.end();
        ++i)
-    if (diff_sptr d = compute_diff_for_types(i->second.first->get_type(),
-                                            i->second.second->get_type(),
-                                            context()))
-      append_child_node(d.get());
+    if (diff_sptr d = i->second)
+      append_child_node(d);
 }
 
 /// Constructor for function_decl_diff
@@ -8476,7 +8789,7 @@ function_decl_diff::return_type_diff() const
 
 /// @return a map of the parameters whose type got changed.  The key
 /// of the map is the name of the type.
-const string_changed_parm_map&
+const string_fn_parm_diff_sptr_map&
 function_decl_diff::subtype_changed_parms() const
 {return priv_->subtype_changed_parms_;}
 
@@ -8522,39 +8835,43 @@ function_decl_diff::has_local_changes() const
     return k & LOCAL_CHANGE_KIND;
   return false;
 }
-/// A comparison functor to compare two changed function parameters
+/// A comparison functor to compare two instances of @ref fn_parm_diff
 /// based on their indexes.
-struct changed_parm_comp
+struct fn_parm_diff_comp
 {
-  /// @param f the first changed function parameter.
+  /// @param f the first diff
   ///
-  /// @param s the second changed function parameter.
+  /// @param s the second diff
   ///
   /// @return true if the index of @p f is less than the index of @p
   /// s.
   bool
-  operator()(const changed_parm& f, const changed_parm& s)
-  {return f.first->get_index() < s.first->get_index();}
-}; // end struct changed_parm_comp;
+  operator()(const fn_parm_diff& f, const fn_parm_diff& s)
+  {return f.first_parameter()->get_index() < s.first_parameter()->get_index();}
 
-/// Sort a map of changed function parameters by the indexes of the
-/// function parameters.
+  bool
+  operator()(const fn_parm_diff_sptr& f, const fn_parm_diff_sptr& s)
+  {return operator()(*f, *s);}
+}; // end struct fn_parm_diff_comp
+
+/// Sort a map of @ref fn_parm_diff by the indexes of the function
+/// parameters.
 ///
 /// @param map the map to sort.
 ///
 /// @param sorted the resulting sorted vector of changed function
 /// parms.
 static void
-sort_changed_parm_map(const unsigned_changed_parm_map& map,
-                     changed_parms_type& sorted)
+sort_string_fn_parm_diff_sptr_map(const unsigned_fn_parm_diff_sptr_map& map,
+                                 vector<fn_parm_diff_sptr>&            sorted)
 {
   sorted.reserve(map.size());
-  for (unsigned_changed_parm_map::const_iterator i = map.begin();
+  for (unsigned_fn_parm_diff_sptr_map::const_iterator i = map.begin();
        i != map.end();
        ++i)
     sorted.push_back(i->second);
 
-  changed_parm_comp comp;
+  fn_parm_diff_comp comp;
   std::sort(sorted.begin(), sorted.end(), comp);
 }
 
@@ -8563,19 +8880,19 @@ sort_changed_parm_map(const unsigned_changed_parm_map& map,
 ///
 /// @param map the map to sort.
 ///
-/// @param sorted the resulting sorted vector of changed function
-/// parms.
+/// @param sorted the resulting sorted vector of instances of @ref
+/// fn_parm_diff_sptr
 static void
-sort_changed_parm_map(const string_changed_parm_map& map,
-                     changed_parms_type& sorted)
+sort_string_fn_parm_diff_sptr_map(const string_fn_parm_diff_sptr_map&  map,
+                                 vector<fn_parm_diff_sptr>&            sorted)
 {
   sorted.reserve(map.size());
-  for (string_changed_parm_map::const_iterator i = map.begin();
+  for (string_fn_parm_diff_sptr_map::const_iterator i = map.begin();
        i != map.end();
        ++i)
     sorted.push_back(i->second);
 
-  changed_parm_comp comp;
+  fn_parm_diff_comp comp;
   std::sort(sorted.begin(), sorted.end(), comp);
 }
 
@@ -8649,58 +8966,36 @@ function_decl_diff::report(ostream& out, const string& indent) const
       priv_->return_type_diff_->report(out, indent + "  ");
     }
 
-  // Hmmh, the above was quick.  Now report about function
-  // parameters; this shouldn't as straightforward.
+  // Hmmh, the above was quick.  Now report about function parameters;
+  // this shouldn't be as straightforward.
   //
   // Report about the parameter types that have changed sub-types.
-  changed_parms_type sorted_fn_parms;
-  sort_changed_parm_map(priv_->subtype_changed_parms_, sorted_fn_parms);
-  for (changed_parms_type::const_iterator i =
+  vector<fn_parm_diff_sptr> sorted_fn_parms;
+  sort_string_fn_parm_diff_sptr_map(priv_->subtype_changed_parms_,
+                                   sorted_fn_parms);
+  for (vector<fn_parm_diff_sptr>::const_iterator i =
         sorted_fn_parms.begin();
        i != sorted_fn_parms.end();
        ++i)
     {
-      diff_sptr d = compute_diff_for_types(i->first->get_type(),
-                                          i->second->get_type(),
-                                          context());
-      if (d)
-       {
-         if (d->to_be_reported())
-           {
-             out << indent
-                 << "parameter " << i->first->get_index()
-                 << " of type '"
-                 << i->first->get_type_pretty_representation()
-                 << "' has sub-type changes:\n";
-             d->report(out, indent + "  ");
-           }
-       }
+      diff_sptr d = *i;
+      if (d && d->to_be_reported())
+       d->report(out, indent);
     }
   // Report about parameters that have changed, while staying
   // compatible -- otherwise they would have changed the mangled name
   // of the function and the function would have been reported as
   // removed.
   sorted_fn_parms.clear();
-  sort_changed_parm_map(priv_->changed_parms_by_id_, sorted_fn_parms);
-  for (changed_parms_type::const_iterator i = sorted_fn_parms.begin();
+  sort_string_fn_parm_diff_sptr_map(priv_->changed_parms_by_id_,
+                                   sorted_fn_parms);
+  for (vector<fn_parm_diff_sptr>::const_iterator i = sorted_fn_parms.begin();
        i != sorted_fn_parms.end();
        ++i)
     {
-      diff_sptr d = compute_diff_for_types(i->first->get_type(),
-                                          i->second->get_type(),
-                                          context());
-      if (d)
-       {
-         if (d->to_be_reported())
-           {
-             out << indent
-                 << "parameter " << i->first->get_index()
-                 << " of type '"
-                 << i->first->get_type_pretty_representation()
-                 << "' changed:\n";
-             d->report(out, indent + "  ");
-           }
-       }
+      diff_sptr d = *i;
+      if (d && d->to_be_reported())
+       d->report(out, indent);
     }
 
   // Report about the parameters that got removed.
@@ -8752,13 +9047,6 @@ compute_diff(const function_decl_sptr first,
       return function_decl_diff_sptr();
     }
 
-  if (diff_sptr dif = ctxt->has_diff_for(first, second))
-    {
-      function_decl_diff_sptr d = dynamic_pointer_cast<function_decl_diff>(dif);
-      assert(d);
-      return d;
-    }
-
   diff_sptr return_type_diff =
     compute_diff_for_types(first->get_return_type(),
                           second->get_return_type(),
@@ -8783,7 +9071,7 @@ compute_diff(const function_decl_sptr first,
 
   result->ensure_lookup_tables_populated();
 
-  ctxt->add_diff(first, second, result);
+  ctxt->initialize_canonical_diff(result);
 
   return result;
 }
@@ -8931,13 +9219,6 @@ compute_diff(const type_decl_sptr        first,
             const type_decl_sptr       second,
             diff_context_sptr          ctxt)
 {
-  if (diff_sptr dif = ctxt->has_diff_for(first, second))
-    {
-      type_decl_diff_sptr d = dynamic_pointer_cast<type_decl_diff>(dif);
-      assert(d);
-      return d;
-    }
-
   type_decl_diff_sptr result(new type_decl_diff(first, second, ctxt));
 
   // We don't need to actually compute a diff here as a type_decl
@@ -8947,7 +9228,7 @@ compute_diff(const type_decl_sptr first,
   // type_decl_diff::length returns 0 if the two type_decls are equal,
   // and 1 otherwise.
 
-  ctxt->add_diff(first, second, result);
+  ctxt->initialize_canonical_diff(result);
 
   return result;
 }
@@ -8972,7 +9253,7 @@ struct typedef_diff::priv
 /// diff::children_node().
 void
 typedef_diff::chain_into_hierarchy()
-{append_child_node(underlying_type_diff().get());}
+{append_child_node(underlying_type_diff());}
 
 /// Constructor for typedef_diff.
 typedef_diff::typedef_diff(const typedef_decl_sptr     first,
@@ -9124,19 +9405,12 @@ compute_diff(const typedef_decl_sptr    first,
             const typedef_decl_sptr    second,
             diff_context_sptr          ctxt)
 {
-  if (diff_sptr dif = ctxt->has_diff_for(first, second))
-    {
-      typedef_diff_sptr d = dynamic_pointer_cast<typedef_diff>(dif);
-      assert(d);
-      return d;
-    }
-
   diff_sptr d = compute_diff_for_types(first->get_underlying_type(),
                                       second->get_underlying_type(),
                                       ctxt);
   typedef_diff_sptr result(new typedef_diff(first, second, d, ctxt));
 
-  ctxt->add_diff(first, second, result);
+  ctxt->initialize_canonical_diff(result);
 
   return result;
 }
@@ -9229,6 +9503,8 @@ compute_diff(const translation_unit_sptr  first,
               sc_diff,
               ctxt);
 
+  ctxt->initialize_canonical_diff(tu_diff);
+
   return tu_diff;
 }
 
@@ -9500,7 +9776,7 @@ struct corpus_diff::priv
 {
   bool                                 finished_;
   string                               pretty_representation_;
-  vector<diff*>                        children_;
+  vector<diff_sptr>                    children_;
   diff_context_sptr                    ctxt_;
   corpus_sptr                          first_;
   corpus_sptr                          second_;
@@ -9513,10 +9789,10 @@ struct corpus_diff::priv
   edit_script                          unrefed_var_syms_edit_script_;
   string_function_ptr_map              deleted_fns_;
   string_function_ptr_map              added_fns_;
-  string_changed_function_ptr_map      changed_fns_;
+  string_function_decl_diff_sptr_map   changed_fns_;
   string_var_ptr_map                   deleted_vars_;
   string_var_ptr_map                   added_vars_;
-  string_changed_var_ptr_map           changed_vars_;
+  string_var_diff_sptr_map             changed_vars_;
   string_elf_symbol_map                added_unrefed_fn_syms_;
   string_elf_symbol_map                deleted_unrefed_fn_syms_;
   string_elf_symbol_map                added_unrefed_var_syms_;
@@ -9622,9 +9898,11 @@ corpus_diff::priv::ensure_lookup_tables_populated()
              deleted_fns_.find(n);
            if (j != deleted_fns_.end())
              {
+               function_decl_sptr f(j->second, noop_deleter());
+               function_decl_sptr s(added_fn, noop_deleter());
+               function_decl_diff_sptr d = compute_diff(f, s, ctxt_);
                if (*j->second != *added_fn)
-                 changed_fns_[j->first] = std::make_pair(j->second,
-                                                         added_fn);
+                 changed_fns_[j->first] = d;
                deleted_fns_.erase(j);
              }
            else
@@ -9709,7 +9987,11 @@ corpus_diff::priv::ensure_lookup_tables_populated()
            if (j != deleted_vars_.end())
              {
                if (*j->second != *added_var)
-                 changed_vars_[n] = std::make_pair(j->second, added_var);
+                 {
+                   var_decl_sptr f(j->second, noop_deleter());
+                   var_decl_sptr s(added_var, noop_deleter());
+                   changed_vars_[n] = compute_diff(f, s, ctxt_);
+                 }
                deleted_vars_.erase(j);
              }
            else
@@ -9870,60 +10152,46 @@ corpus_diff::priv::apply_filters_and_compute_diff_stats(diff_stats& stat)
   // Walk the changed function diff nodes to apply the categorization
   // filters.
   diff_sptr diff;
-  for (string_changed_function_ptr_map::const_iterator i =
+  for (string_function_decl_diff_sptr_map::const_iterator i =
         changed_fns_.begin();
        i != changed_fns_.end();
        ++i)
     {
-      function_decl_sptr f(i->second.first, noop_deleter());
-      function_decl_sptr s(i->second.second, noop_deleter());
-      diff = compute_diff(f, s, ctxt_);
-      ctxt_->maybe_apply_filters(diff, /*traverse_nodes_once=*/false);
+      diff_sptr diff = i->second;
+      ctxt_->maybe_apply_filters(diff);
     }
 
   // Walk the changed variable diff nodes to apply the categorization
   // filters.
-  for (string_changed_var_ptr_map::const_iterator i = changed_vars_.begin();
+  for (string_var_diff_sptr_map::const_iterator i = changed_vars_.begin();
        i != changed_vars_.end();
        ++i)
     {
-      var_decl_sptr f(i->second.first, noop_deleter());
-      var_decl_sptr s(i->second.second, noop_deleter());
-      diff = compute_diff_for_decls(f, s, ctxt_);
-      ctxt_->maybe_apply_filters(diff, /*traverse_nodes_once=*/false);
+      diff_sptr diff = i->second;
+      ctxt_->maybe_apply_filters(diff);
     }
 
   categorize_redundant_changed_sub_nodes();
 
   // Walk the changed function diff nodes to count the number of
   // filtered-out functions.
-  for (string_changed_function_ptr_map::const_iterator i =
+  for (string_function_decl_diff_sptr_map::const_iterator i =
         changed_fns_.begin();
        i != changed_fns_.end();
        ++i)
-    {
-      function_decl_sptr f(i->second.first, noop_deleter());
-      function_decl_sptr s(i->second.second, noop_deleter());
-      diff = compute_diff(f, s, ctxt_);
-      if (diff->is_filtered_out())
-       stat.num_func_filtered_out(stat.num_func_filtered_out() + 1);
-    }
+    if (i->second->is_filtered_out())
+      stat.num_func_filtered_out(stat.num_func_filtered_out() + 1);
 
   // Walk the changed variables diff nodes to count the number of
   // filtered-out variables.
-  for (string_changed_var_ptr_map::const_iterator i = changed_vars_.begin();
+  for (string_var_diff_sptr_map::const_iterator i = changed_vars_.begin();
        i != changed_vars_.end();
        ++i)
     {
-      var_decl_sptr f(i->second.first, noop_deleter());
-      var_decl_sptr s(i->second.second, noop_deleter());
-      diff = compute_diff_for_decls(f, s, ctxt_);
-      if (diff->is_filtered_out())
+      if (i->second->is_filtered_out())
        stat.num_vars_filtered_out(stat.num_vars_filtered_out() + 1);
     }
 
-  clear_redundancy_categorization();
-
   stat.num_func_syms_added(added_unrefed_fn_syms_.size());
   stat.num_func_syms_removed(deleted_unrefed_fn_syms_.size());
   stat.num_var_syms_added(added_unrefed_var_syms_.size());
@@ -10033,23 +10301,19 @@ corpus_diff::priv::categorize_redundant_changed_sub_nodes()
   diff_sptr diff;
 
   ctxt_->forget_traversed_diffs();
-  for (string_changed_function_ptr_map::const_iterator i = changed_fns_.begin();
+  for (string_function_decl_diff_sptr_map::const_iterator i = changed_fns_.begin();
        i!= changed_fns_.end();
        ++i)
     {
-      function_decl_sptr f(i->second.first, noop_deleter());
-      function_decl_sptr s(i->second.second, noop_deleter());
-      diff = compute_diff(f, s, ctxt_);
+      diff = i->second;
       categorize_redundancy(diff);
     }
 
-  for (string_changed_var_ptr_map::const_iterator i = changed_vars_.begin();
+  for (string_var_diff_sptr_map::const_iterator i = changed_vars_.begin();
        i!= changed_vars_.end();
        ++i)
     {
-      var_decl_sptr f(i->second.first, noop_deleter());
-      var_decl_sptr s(i->second.second, noop_deleter());
-      diff = compute_diff(f, s, ctxt_);
+      diff_sptr diff = i->second;
       categorize_redundancy(diff);
     }
 }
@@ -10060,23 +10324,20 @@ void
 corpus_diff::priv::clear_redundancy_categorization()
 {
   diff_sptr diff;
-  for (string_changed_function_ptr_map::const_iterator i = changed_fns_.begin();
+  for (string_function_decl_diff_sptr_map::const_iterator i =
+        changed_fns_.begin();
        i!= changed_fns_.end();
        ++i)
     {
-      function_decl_sptr f(i->second.first, noop_deleter());
-      function_decl_sptr s(i->second.second, noop_deleter());
-      diff = compute_diff(f, s, ctxt_);
+      diff = i->second;
       abigail::comparison::clear_redundancy_categorization(diff);
     }
 
-  for (string_changed_var_ptr_map::const_iterator i = changed_vars_.begin();
+  for (string_var_diff_sptr_map::const_iterator i = changed_vars_.begin();
        i!= changed_vars_.end();
        ++i)
     {
-      var_decl_sptr f(i->second.first, noop_deleter());
-      var_decl_sptr s(i->second.second, noop_deleter());
-      diff = compute_diff(f, s, ctxt_);
+      diff = i->second;
       abigail::comparison::clear_redundancy_categorization(diff);
     }
 }
@@ -10088,17 +10349,12 @@ corpus_diff::priv::clear_redundancy_categorization()
 void
 corpus_diff::chain_into_hierarchy()
 {
-  for (string_changed_function_ptr_map::const_iterator i =
+  for (string_function_decl_diff_sptr_map::const_iterator i =
         changed_functions().begin();
        i != changed_functions().end();
        ++i)
-    {
-      function_decl_sptr f(i->second.first, noop_deleter());
-      function_decl_sptr s(i->second.second, noop_deleter());
-
-      if (diff_sptr d = compute_diff_for_decls(f,s, context()))
-       append_child_node(d.get());
-    }
+    if (diff_sptr d = i->second)
+      append_child_node(d);
 }
 
 /// Constructor for @ref corpus_diff.
@@ -10139,14 +10395,18 @@ corpus_diff::second_corpus() const
 {return priv_->second_;}
 
 /// @return the children nodes of the current instance of corpus_diff.
-const vector<diff*>&
-corpus_diff::chidren_nodes() const
+const vector<diff_sptr>&
+corpus_diff::children_nodes() const
 {return priv_->children_;}
 
 /// Append a new child node to the vector of childre nodes for the
 /// current instance of @ref corpus_diff node.
+///
+/// @param d the new child node.  Note that the life time of the
+/// object held by @p d will thus equal the life time of the current
+/// instance of @ref corpus_diff.
 void
-corpus_diff::append_child_node(diff* d)
+corpus_diff::append_child_node(diff_sptr d)
 {
   assert(d);
   priv_->children_.push_back(d);
@@ -10190,7 +10450,7 @@ corpus_diff::added_functions()
 ///
 /// @return functions which signature didn't change, but which
 /// do have some indirect changes in their parms.
-const string_changed_function_ptr_map&
+const string_function_decl_diff_sptr_map&
 corpus_diff::changed_functions()
 {return priv_->changed_fns_;}
 
@@ -10213,7 +10473,7 @@ corpus_diff::added_variables() const
 /// do have some indirect changes in some sub-types.
 ///
 /// @return the changed variables.
-const string_changed_var_ptr_map&
+const string_var_diff_sptr_map&
 corpus_diff::changed_variables()
 {return priv_->changed_vars_;}
 
@@ -10378,25 +10638,26 @@ sort_string_function_ptr_map(const string_function_ptr_map& map,
   std::sort(sorted.begin(), sorted.end(), comp);
 }
 
-/// A "Less Than"functor to compare instances of @ref
-/// changed_function_ptr.
-struct changed_function_ptr_comp
+/// A "Less Than" functor to compare instance of @ref
+/// function_decl_diff.
+struct function_decl_diff_comp
 {
   /// The actual less than operator.
   ///
-  /// It returns true if the first @ref changed_function_ptr is less
+  /// It returns true if the first @ref function_decl_diff is less
   /// than the second one.
   ///
-  /// param first the first @ref changed_function_ptr to consider.
+  /// param first the first @ref function_decl_diff to consider.
   ///
-  /// @param second the second @ref changed_function_ptr to consider.
+  /// @param second the second @ref function_decl_diff to consider.
   ///
   /// @return true iff @p first is less than @p second.
   bool
-  operator()(const changed_function_ptr& first,
-            const changed_function_ptr& second)
+  operator()(const function_decl_diff& first,
+            const function_decl_diff& second)
   {
-    function_decl *f = first.first, *s = second.first;
+    function_decl_sptr f = first.first_function_decl(),
+      s = second.first_function_decl();
 
     string fr = f->get_qualified_name(),
       sr = s->get_qualified_name();
@@ -10408,7 +10669,7 @@ struct changed_function_ptr_comp
        else if (!f->get_linkage_name().empty())
          fr = f->get_linkage_name();
        else
-         f->get_pretty_representation();
+         fr = f->get_pretty_representation();
 
        if (s->get_symbol())
          sr = s->get_symbol()->get_id_string();
@@ -10418,31 +10679,50 @@ struct changed_function_ptr_comp
          sr = s->get_pretty_representation();
       }
 
-    return fr < sr;
+    return (fr.compare(sr) < 0);
   }
-}; // end struct changed_function_comp
 
-/// Sort a instance of @ref string_changed_function_ptr_map map and
-/// stuff a sorted vector of @ref changed_function_ptr as a result.
+  /// The actual less than operator.
+  ///
+  /// It returns true if the first @ref function_decl_diff_sptr is
+  /// less than the second one.
+  ///
+  /// param first the first @ref function_decl_diff_sptr to consider.
+  ///
+  /// @param second the second @ref function_decl_diff_sptr to
+  /// consider.
+  ///
+  /// @return true iff @p first is less than @p second.
+  bool
+  operator()(const function_decl_diff_sptr first,
+            const function_decl_diff_sptr second)
+  {return operator()(*first, *second);}
+}; // end struct function_decl_diff_comp
+
+/// Sort the values of a @ref string_function_decl_diff_sptr_map map
+/// and store the result in a vector of @ref function_decl_diff_sptr
+/// objects.
 ///
-/// @param map the map to sort.
+/// @param map the map whose values to store.
 ///
-/// @param sorted the resulting sorted vector.
+/// @param sorted the vector of function_decl_diff_sptr to store the
+/// result of the sort into.
 static void
-sort_string_changed_function_ptr_map(const string_changed_function_ptr_map& map,
-                                    vector<changed_function_ptr>& sorted)
+sort_string_function_decl_diff_sptr_map
+(const string_function_decl_diff_sptr_map& map,
+ vector<function_decl_diff_sptr>& sorted)
 {
   sorted.reserve(map.size());
-  for (string_changed_function_ptr_map::const_iterator i = map.begin();
+  for (string_function_decl_diff_sptr_map::const_iterator i = map.begin();
        i != map.end();
        ++i)
     sorted.push_back(i->second);
-  changed_function_ptr_comp comp;
+  function_decl_diff_comp comp;
   std::sort(sorted.begin(), sorted.end(), comp);
 }
 
-/// Functor to sort instances of @ref changed_var_ptr.
-struct changed_vars_comp
+/// Functor to sort instances of @ref var_diff_sptr
+struct var_diff_sptr_comp
 {
   /// Return true if the first argument is less than the second one.
   ///
@@ -10452,31 +10732,31 @@ struct changed_vars_comp
   ///
   /// @return true if @p f is less than @p s.
   bool
-  operator()(const changed_var_ptr& f,
-            const changed_var_ptr& s)
+  operator()(const var_diff_sptr f,
+            const var_diff_sptr s)
   {
-    return (f.first->get_qualified_name()
-           < s.first->get_qualified_name());
+    return (f->first_var()->get_qualified_name()
+           < s->first_var()->get_qualified_name());
   }
-}; // end struct changed_vars_comp
+}; // end struct var_diff_sptr_comp
 
-/// Sort of an instance of @ref changed_var_ptr_map map.
+/// Sort of an instance of @ref string_var_diff_sptr_map map.
 ///
 /// @param map the input map to sort.
 ///
-/// @param sorted the ouptut sorted vector of @ref changed_var_ptr.
+/// @param sorted the ouptut sorted vector of @ref var_diff_sptr.
 /// It's populated with the sorted content.
 static void
-sort_changed_vars(const string_changed_var_ptr_map& map,
-                 vector<changed_var_ptr>& sorted)
+sort_string_var_diff_sptr_map(const string_var_diff_sptr_map& map,
+                             vector<var_diff_sptr>& sorted)
 {
   sorted.reserve(map.size());
-  for (string_changed_var_ptr_map::const_iterator i = map.begin();
+  for (string_var_diff_sptr_map::const_iterator i = map.begin();
        i != map.end();
        ++i)
     sorted.push_back(i->second);
 
-  changed_vars_comp comp;
+  var_diff_sptr_comp comp;
   std::sort(sorted.begin(), sorted.end(), comp);
 }
 
@@ -10651,27 +10931,22 @@ corpus_diff::report(ostream& out, const string& indent) const
            << " functions with some indirect sub-type change:\n\n";
 
       bool emitted = false;
-      vector<changed_function_ptr> sorted_changed_fns;
-      sort_string_changed_function_ptr_map(priv_->changed_fns_,
-                                          sorted_changed_fns);
-      for (vector<changed_function_ptr>::const_iterator i =
+      vector<function_decl_diff_sptr> sorted_changed_fns;
+      sort_string_function_decl_diff_sptr_map(priv_->changed_fns_,
+                                             sorted_changed_fns);
+      for (vector<function_decl_diff_sptr>::const_iterator i =
             sorted_changed_fns.begin();
           i != sorted_changed_fns.end();
           ++i)
        {
-         function_decl_sptr f(i->first, noop_deleter());
-         function_decl_sptr s(i->second, noop_deleter());
-
-         diff_sptr diff = compute_diff(f, s, context());
+         diff_sptr diff = *i;
          if (!diff)
            continue;
 
-         categorize_redundancy(diff);
-
          if (diff->to_be_reported())
            {
              out << indent << "  [C]'"
-                 << i->first->get_pretty_representation()
+                 << (*i)->first_function_decl()->get_pretty_representation()
                  << "' has some indirect sub-type changes:\n";
              diff->report(out, indent + "    ");
              emitted |= true;
@@ -10772,27 +11047,23 @@ corpus_diff::report(ostream& out, const string& indent) const
            << " Changed variables:\n\n";
       string n1, n2;
 
-      vector<changed_var_ptr> sorted_changed_vars;
-      sort_changed_vars(priv_->changed_vars_, sorted_changed_vars);
-      for (vector<changed_var_ptr>::const_iterator i =
+      vector<var_diff_sptr> sorted_changed_vars;
+      sort_string_var_diff_sptr_map(priv_->changed_vars_, sorted_changed_vars);
+      for (vector<var_diff_sptr>::const_iterator i =
             sorted_changed_vars.begin();
           i != sorted_changed_vars.end();
           ++i)
        {
-         var_decl_sptr f(i->first, noop_deleter());
-         var_decl_sptr s(i->second, noop_deleter());
-         diff_sptr diff = compute_diff_for_decls(f, s, context());
+         diff_sptr diff = *i;
 
          if (!diff)
            continue;
 
-         categorize_redundancy(diff);
-
          if (!diff->to_be_reported())
            continue;
 
-         n1 = f->get_pretty_representation();
-         n2 = s->get_pretty_representation();
+         n1 = diff->first_subject()->get_pretty_representation();
+         n2 = diff->second_subject()->get_pretty_representation();
 
          out << indent << "  '" << n1 << "' was changed";
          if (n1 != n2)
@@ -10940,14 +11211,12 @@ corpus_diff::traverse(diff_node_visitor& v)
       return false;
     }
 
-  for (string_changed_function_ptr_map::const_iterator i =
+  for (string_function_decl_diff_sptr_map::const_iterator i =
         changed_functions().begin();
        i != changed_functions().end();
        ++i)
     {
-      function_decl_sptr f(i->second.first, noop_deleter());
-      function_decl_sptr s(i->second.second, noop_deleter());
-      if (diff_sptr d = compute_diff_for_decls(f,s, context()))
+      if (diff_sptr d = i->second)
        {
          if (!d->traverse(v))
            {
@@ -10957,14 +11226,12 @@ corpus_diff::traverse(diff_node_visitor& v)
        }
     }
 
-  for (string_changed_var_ptr_map::const_iterator i =
+  for (string_var_diff_sptr_map::const_iterator i =
         changed_variables().begin();
        i != changed_variables().end();
        ++i)
     {
-      var_decl_sptr f(i->second.first, noop_deleter());
-      var_decl_sptr s(i->second.second, noop_deleter());
-      if (diff_sptr d = compute_diff_for_decls(f,s, context()))
+      if (diff_sptr d = i->second)
        {
          if (!d->traverse(v))
            {
@@ -11034,6 +11301,7 @@ compute_diff(const corpus_sptr  f,
 
   return r;
 }
+
 // </corpus stuff>
 
 // <diff_node_visitor stuff>
@@ -11261,7 +11529,7 @@ struct category_propagation_visitor : public diff_node_visitor
   virtual void
   visit_end(diff* d)
   {
-    for (vector<diff*>::const_iterator i = d->children_nodes().begin();
+    for (vector<diff_sptr>::const_iterator i = d->children_nodes().begin();
         i != d->children_nodes().end();
         ++i)
       {
@@ -11366,11 +11634,11 @@ struct suppression_categorization_visitor : public diff_node_visitor
     if (!(d->get_category() & SUPPRESSED_CATEGORY)
        && !d->has_local_changes())
       {
-       for (vector<diff*>::const_iterator i = d->children_nodes().begin();
+       for (vector<diff_sptr>::const_iterator i = d->children_nodes().begin();
             i != d->children_nodes().end();
             ++i)
          {
-           diff* child = *i;
+           diff_sptr child = *i;
            if (child->length())
              {
                has_non_empty_child = true;
@@ -11619,7 +11887,8 @@ struct redundancy_marking_visitor : public diff_node_visitor
          {
            bool has_non_redundant_child = false;
            bool has_non_empty_child = false;
-           for (vector<diff*>::const_iterator i = d->children_nodes().begin();
+           for (vector<diff_sptr>::const_iterator i =
+                  d->children_nodes().begin();
                 i != d->children_nodes().end();
                 ++i)
              {
@@ -11783,8 +12052,7 @@ clear_redundancy_categorization(corpus_diff_sptr diff_tree)
 void
 apply_filters(corpus_diff_sptr diff_tree)
 {
-  diff_tree->context()->maybe_apply_filters(diff_tree,
-                                           /*traverse_nodes_once=*/false);
+  diff_tree->context()->maybe_apply_filters(diff_tree);
   propagate_categories(diff_tree);
 }
 
index 7d9ad2a38f1116aec72401f4ce5367acf5f89b80..5b9406b36c56d9abced9c62393c6931e630f7423 100644 (file)
@@ -436,20 +436,28 @@ size_t
 function_decl::hash::operator()(const function_decl* t) const
 {return operator()(*t);}
 
-struct function_decl::parameter::hash
+size_t
+function_decl::parameter::hash::operator()
+  (const function_decl::parameter& p) const
 {
-  size_t
-  operator()(const function_decl::parameter& p) const
-  {
-    type_base::shared_ptr_hash hash_type_ptr;
-    std::tr1::hash<bool> hash_bool;
-    std::tr1::hash<unsigned> hash_unsigned;
-    size_t v = hash_type_ptr(p.get_type());
-    v = hashing::combine_hashes(v, hash_unsigned(p.get_index()));
-    v = hashing::combine_hashes(v, hash_bool(p.get_variadic_marker()));
-    return v;
-  }
-};
+  type_base::shared_ptr_hash hash_type_ptr;
+  std::tr1::hash<bool> hash_bool;
+  std::tr1::hash<unsigned> hash_unsigned;
+  size_t v = hash_type_ptr(p.get_type());
+  v = hashing::combine_hashes(v, hash_unsigned(p.get_index()));
+  v = hashing::combine_hashes(v, hash_bool(p.get_variadic_marker()));
+  return v;
+}
+
+size_t
+function_decl::parameter::hash::operator()
+  (const function_decl::parameter* p) const
+{return operator()(*p);}
+
+size_t
+function_decl::parameter::hash::operator()
+  (const function_decl::parameter_sptr p) const
+{return operator()(p.get());}
 
 /// Hashing functor for the @ref method_type type.
 struct method_type::hash
index 198133dba251256e30492bc56eac28e7fe99c673..764cbd65810e5f36982766636d26e157a3479e94 100644 (file)
@@ -5734,16 +5734,7 @@ struct function_decl::priv
   {}
 }; // end sruct function_decl::priv
 
-/// Get a name uniquely identifying the parameter in the function.
-///
-///@return the unique parm name id.
-const string
-function_decl::parameter::get_name_id() const
-{
-  std::ostringstream o;
-  o << get_type_name() << "-" << get_index();
-  return o.str();
-}
+
 
 function_decl::function_decl(const std::string& name,
                             function_type_sptr function_type,
@@ -5756,7 +5747,6 @@ function_decl::function_decl(const std::string& name,
     priv_(new priv(function_type, declared_inline, bind))
 {}
 
-
 /// Constructor of the function_decl type.
 ///
 /// This flavour of constructor is for when the pointer to the
@@ -6183,6 +6173,211 @@ function_decl::~function_decl()
 
 // <function_decl definitions>
 
+// <function_decl::parameter definitions>
+
+struct function_decl::parameter::priv
+{
+  type_base_wptr       type_;
+  unsigned             index_;
+  bool                 variadic_marker_;
+  bool                 artificial_;
+
+  priv()
+    : index_(),
+      variadic_marker_(),
+      artificial_()
+  {}
+
+  priv(type_base_sptr type,
+       unsigned index,
+       bool variadic_marker,
+       bool artificial)
+    : type_(type),
+      index_(index),
+      variadic_marker_(variadic_marker),
+      artificial_(artificial)
+  {}
+};// end struct function_decl::parameter::priv
+
+function_decl::parameter::parameter(const type_base_sptr       type,
+                                   unsigned                    index,
+                                   const std::string&          name,
+                                   location                    loc,
+                                   bool                        is_variadic)
+  : decl_base(name, loc),
+    priv_(new priv(type, index, is_variadic, /*is_artificial=*/false))
+{}
+
+function_decl::parameter::parameter(const type_base_sptr       type,
+                                   unsigned                    index,
+                                   const std::string&          name,
+                                   location                    loc,
+                                   bool                        is_variadic,
+                                   bool                        is_artificial)
+  : decl_base(name, loc),
+    priv_(new priv(type, index, is_variadic, is_artificial))
+{}
+
+function_decl::parameter::parameter(const type_base_sptr       type,
+                                   const std::string&          name,
+                                   location                    loc,
+                                   bool                        is_variadic,
+                                   bool                        is_artificial)
+  : decl_base(name, loc),
+    priv_(new priv(type, 0, is_variadic, is_artificial))
+{}
+
+function_decl::parameter::parameter(const type_base_sptr       type,
+                                   unsigned                    index,
+                                   bool                        variad)
+  : decl_base("", location()),
+    priv_(new priv(type, index, variad, /*is_artificial=*/false))
+{}
+
+const type_base_sptr
+function_decl::parameter::get_type()const
+{
+  if (priv_->type_.expired())
+    return type_base_sptr();
+  return type_base_sptr(priv_->type_);
+}
+
+/// @return a copy of the type name of the parameter.
+const string
+function_decl::parameter::get_type_name() const
+{
+  string str;
+  if (get_variadic_marker())
+    str = "...";
+  else
+    {
+       type_base_sptr t = get_type();
+       assert(t);
+       str += abigail::ir::get_type_name(t);
+    }
+  return str;
+}
+
+/// @return a copy of the pretty representation of the type of the
+/// parameter.
+const string
+function_decl::parameter::get_type_pretty_representation() const
+{
+  string str;
+  if (get_variadic_marker())
+    str = "...";
+  else
+    {
+       type_base_sptr t = get_type();
+       assert(t);
+       str += get_type_declaration(t)->get_pretty_representation();
+    }
+  return str;
+}
+
+/// Get a name uniquely identifying the parameter in the function.
+///
+///@return the unique parm name id.
+const string
+function_decl::parameter::get_name_id() const
+{
+  std::ostringstream o;
+  o << get_type_name() << "-" << get_index();
+  return o.str();
+}
+
+unsigned
+function_decl::parameter::get_index() const
+{return priv_->index_;}
+
+void
+function_decl::parameter::set_index(unsigned i)
+{priv_->index_ = i;}
+
+/// Test if the parameter is artificial.
+///
+/// Being artificial means the parameter was not explicitely
+/// mentionned in the source code, but was rather artificially
+/// created by the compiler.
+///
+/// @return true if the parameter is artificial, false otherwise.
+bool
+function_decl::parameter::get_artificial() const
+{return priv_->artificial_;}
+
+bool
+function_decl::parameter::get_variadic_marker() const
+{return priv_->variadic_marker_;}
+
+/// Getter for the artificial-ness of the parameter.
+///
+/// Being artificial means the parameter was not explicitely
+/// mentionned in the source code, but was rather artificially
+/// created by the compiler.
+///
+/// @param f set to true if the parameter is artificial.
+void
+function_decl::parameter::set_artificial(bool f)
+{priv_->artificial_ = f;}
+
+bool
+equals(const function_decl::parameter& l,
+       const function_decl::parameter& r,
+       change_kind& k)
+{
+  bool result = true;
+
+  if ((l.get_variadic_marker() != r.get_variadic_marker())
+      || (l.get_index() != r.get_index())
+      || (!!l.get_type() != !!r.get_type()))
+    {
+      result = false;
+      k |= LOCAL_CHANGE_KIND;
+    }
+
+  if (l.get_type() != r.get_type())
+    {
+      result = false;
+      k |= SUBTYPE_CHANGE_KIND;
+    }
+
+  return result;
+}
+
+bool
+function_decl::parameter::operator==(const parameter& o) const
+{
+  change_kind k = NO_CHANGE_KIND;
+  return equals(*this, o, k);
+}
+
+bool
+function_decl::parameter::operator==(const decl_base& o) const
+{
+  const function_decl::parameter* p =
+    dynamic_cast<const function_decl::parameter*>(&o);
+  if (!p)
+    return false;
+  return function_decl::parameter::operator==(*p);
+}
+
+bool
+function_decl::parameter::traverse(ir_node_visitor& v)
+{return v.visit(this);}
+
+size_t
+function_decl::parameter::get_hash() const
+{
+  function_decl::parameter::hash hash_fn_parm;
+  return hash_fn_parm(this);
+}
+
+void
+function_decl::parameter::get_qualified_name(string& qualified_name) const
+{qualified_name = get_name();}
+
+// </function_decl::parameter definitions>
+
 // <class_decl definitions>
 
 static void
@@ -8417,6 +8612,9 @@ bool
 ir_node_visitor::visit(function_decl*)
 {return true;}
 
+bool
+ir_node_visitor::visit(function_decl::parameter*)
+{return true;}
 bool
 ir_node_visitor::visit(function_tdecl*)
 {return true;}
index 277d175f4b397f3079221ba42f3168996481a7b2..4ed7214b1e833ab864072edcf917420a297cce8a 100644 (file)
@@ -175,6 +175,16 @@ test-diff-dwarf/libtest20-add-fn-parm-v1.so \
 test-diff-dwarf/test20-add-fn-parm-report-0.txt \
 test-diff-dwarf/test20-add-fn-parm-v0.c \
 test-diff-dwarf/test20-add-fn-parm-v1.c \
+test-diff-dwarf/libtest21-redundant-fn-v0.so \
+test-diff-dwarf/libtest21-redundant-fn-v1.so \
+test-diff-dwarf/test21-redundant-fn-report-0.txt \
+test-diff-dwarf/test21-redundant-fn-v0.cc \
+test-diff-dwarf/test21-redundant-fn-v1.cc \
+test-diff-dwarf/libtest22-changed-parm-c-v0.so \
+test-diff-dwarf/libtest22-changed-parm-c-v1.so \
+test-diff-dwarf/test22-changed-parm-c-report-0.txt \
+test-diff-dwarf/test22-changed-parm-c-v0.c \
+test-diff-dwarf/test22-changed-parm-c-v1.c \
 \
 test-read-dwarf/test0                  \
 test-read-dwarf/test0.abi                      \
@@ -439,6 +449,18 @@ test-diff-suppr/test7-var-suppr-report-6.txt \
 test-diff-suppr/test7-var-suppr-report-7.txt \
 test-diff-suppr/test7-var-suppr-report-8.txt \
 test-diff-suppr/test7-var-suppr-version-script \
+test-diff-suppr/libtest8-redundant-fn-v0.so \
+test-diff-suppr/libtest8-redundant-fn-v1.so \
+test-diff-suppr/test8-redundant-fn-report-0.txt \
+test-diff-suppr/test8-redundant-fn-report-1.txt \
+test-diff-suppr/test8-redundant-fn-v0.cc \
+test-diff-suppr/test8-redundant-fn-v1.cc \
+test-diff-suppr/libtest9-changed-parm-c-v0.so \
+test-diff-suppr/libtest9-changed-parm-c-v1.so \
+test-diff-suppr/test9-changed-parm-c-report-0.txt \
+test-diff-suppr/test9-changed-parm-c-report-1.txt \
+test-diff-suppr/test9-changed-parm-c-v0.c \
+test-diff-suppr/test9-changed-parm-c-v1.c \
 \
 test-lookup-syms/test0.cc                      \
 test-lookup-syms/test0.o                       \
index 910c2c6c0215be2728760f612568e2f713efed4a..c598ece19618c632ce57a39d4d07f637ff2be4b3 100644 (file)
@@ -4,14 +4,14 @@ Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
 
 2 functions with some indirect sub-type change:
 
-  [C]'function libapp::S0* libapp::create_s0()' has some indirect sub-type changes:
-    return type changed:
-      in pointed to type 'struct libapp::S0':
+  [C]'function int libapp::fun0(libapp::S0&)' has some indirect sub-type changes:
+    parameter 0 of type 'libapp::S0&' has sub-type changes:
+      in referenced type 'struct libapp::S0':
         size changed from 32 to 64 bits
         1 data member insertion:
           'char libapp::S0::m1', at offset 32 (in bits)
-  [C]'function libapp::S1* libapp::create_s1()' has some indirect sub-type changes:
-    return type changed:
+  [C]'function void libapp::fun1(libapp::S1*)' has some indirect sub-type changes:
+    parameter 0 of type 'libapp::S1*' has sub-type changes:
       in pointed to type 'struct libapp::S1':
         size changed from 32 to 96 bits
         2 data member insertions:
diff --git a/tests/data/test-diff-dwarf/libtest21-redundant-fn-v0.so b/tests/data/test-diff-dwarf/libtest21-redundant-fn-v0.so
new file mode 100755 (executable)
index 0000000..8a9fa3c
Binary files /dev/null and b/tests/data/test-diff-dwarf/libtest21-redundant-fn-v0.so differ
diff --git a/tests/data/test-diff-dwarf/libtest21-redundant-fn-v1.so b/tests/data/test-diff-dwarf/libtest21-redundant-fn-v1.so
new file mode 100755 (executable)
index 0000000..e1e819f
Binary files /dev/null and b/tests/data/test-diff-dwarf/libtest21-redundant-fn-v1.so differ
diff --git a/tests/data/test-diff-dwarf/libtest22-changed-parm-c-v0.so b/tests/data/test-diff-dwarf/libtest22-changed-parm-c-v0.so
new file mode 100755 (executable)
index 0000000..1516592
Binary files /dev/null and b/tests/data/test-diff-dwarf/libtest22-changed-parm-c-v0.so differ
diff --git a/tests/data/test-diff-dwarf/libtest22-changed-parm-c-v1.so b/tests/data/test-diff-dwarf/libtest22-changed-parm-c-v1.so
new file mode 100755 (executable)
index 0000000..73eb8c4
Binary files /dev/null and b/tests/data/test-diff-dwarf/libtest22-changed-parm-c-v1.so differ
diff --git a/tests/data/test-diff-dwarf/test21-redundant-fn-report-0.txt b/tests/data/test-diff-dwarf/test21-redundant-fn-report-0.txt
new file mode 100644 (file)
index 0000000..3b6471e
--- /dev/null
@@ -0,0 +1,15 @@
+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 bar(S&)' has some indirect sub-type changes:
+    parameter 0 of type 'S&' has sub-type changes:
+      in referenced type 'struct S':
+        size changed from 32 to 64 bits
+        1 data member insertion:
+          'char S::m1', at offset 32 (in bits)
+  [C]'function void foo(S*)' has some indirect sub-type changes:
+    parameter 0 of type 'S*' has sub-type changes:
+      pointed to type 'struct S' changed, as reported earlier
+
diff --git a/tests/data/test-diff-dwarf/test21-redundant-fn-v0.cc b/tests/data/test-diff-dwarf/test21-redundant-fn-v0.cc
new file mode 100644 (file)
index 0000000..498e11b
--- /dev/null
@@ -0,0 +1,16 @@
+// gcc -g -Wall -shared -o libtest21-redundant-fn-v0.so test21-redundant-fn-v0.cc 
+
+struct S
+{
+  int m0;
+};
+
+void
+foo(S*)
+{
+}
+
+void
+bar(S&)
+{
+}
diff --git a/tests/data/test-diff-dwarf/test21-redundant-fn-v1.cc b/tests/data/test-diff-dwarf/test21-redundant-fn-v1.cc
new file mode 100644 (file)
index 0000000..52890cc
--- /dev/null
@@ -0,0 +1,17 @@
+// gcc -g -Wall -shared -o libtest21-redundant-fn-v1.so test21-redundant-fn-v1.cc 
+
+struct S
+{
+  int m0;
+  char m1;
+};
+
+void
+foo(S*)
+{
+}
+
+void
+bar(S&)
+{
+}
diff --git a/tests/data/test-diff-dwarf/test22-changed-parm-c-report-0.txt b/tests/data/test-diff-dwarf/test22-changed-parm-c-report-0.txt
new file mode 100644 (file)
index 0000000..60ac22d
--- /dev/null
@@ -0,0 +1,11 @@
+Functions changes summary: 0 Removed, 1 Changed, 0 Added function
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+1 function with some indirect sub-type change:
+
+  [C]'function int foo(int)' has some indirect sub-type changes:
+    parameter 0 of type 'int' changed:
+      name changed from 'int' to 'char'
+      size changed from 32 to 8 bits
+      alignment changed from 32 to 8 bits
+
diff --git a/tests/data/test-diff-dwarf/test22-changed-parm-c-v0.c b/tests/data/test-diff-dwarf/test22-changed-parm-c-v0.c
new file mode 100644 (file)
index 0000000..36bb792
--- /dev/null
@@ -0,0 +1,7 @@
+/*
+  Compile with:
+     gcc -g -Wall -shared -o libtest22-changed-parm-c-v0.so test22-changed-parm-c-v0.c  */
+
+int
+foo(int a)
+{return a;}
diff --git a/tests/data/test-diff-dwarf/test22-changed-parm-c-v1.c b/tests/data/test-diff-dwarf/test22-changed-parm-c-v1.c
new file mode 100644 (file)
index 0000000..81b5a85
--- /dev/null
@@ -0,0 +1,7 @@
+/*
+  compile with:
+    gcc -g -Wall -shared -o libtest22-changed-parm-c-v1.so test22-changed-parm-c-v1.c 
+ */
+int
+foo(char a)
+{return a;}
diff --git a/tests/data/test-diff-suppr/libtest8-redundant-fn-v0.so b/tests/data/test-diff-suppr/libtest8-redundant-fn-v0.so
new file mode 100755 (executable)
index 0000000..8a9fa3c
Binary files /dev/null and b/tests/data/test-diff-suppr/libtest8-redundant-fn-v0.so differ
diff --git a/tests/data/test-diff-suppr/libtest8-redundant-fn-v1.so b/tests/data/test-diff-suppr/libtest8-redundant-fn-v1.so
new file mode 100755 (executable)
index 0000000..e1e819f
Binary files /dev/null and b/tests/data/test-diff-suppr/libtest8-redundant-fn-v1.so differ
diff --git a/tests/data/test-diff-suppr/libtest9-changed-parm-c-v0.so b/tests/data/test-diff-suppr/libtest9-changed-parm-c-v0.so
new file mode 100755 (executable)
index 0000000..1516592
Binary files /dev/null and b/tests/data/test-diff-suppr/libtest9-changed-parm-c-v0.so differ
diff --git a/tests/data/test-diff-suppr/libtest9-changed-parm-c-v1.so b/tests/data/test-diff-suppr/libtest9-changed-parm-c-v1.so
new file mode 100755 (executable)
index 0000000..73eb8c4
Binary files /dev/null and b/tests/data/test-diff-suppr/libtest9-changed-parm-c-v1.so differ
index b73d38d691fb7b181da6d551c72ba50059a01717..5e3b47805629bb1146221b2a5d6484233bc3e0bf 100644 (file)
@@ -3,13 +3,12 @@ Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
 
 1 function with some indirect sub-type change:
 
-  [C]'function void bar(S*)' has some indirect sub-type changes:
-    parameter 0 of type 'S*' has sub-type changes:
-      in pointed to type 'struct S':
-        size changed from 32 to 64 bits
-        1 data member insertion:
-          'char S::m0', at offset 0 (in bits)
-        1 data member change:
-         'int S::m1' offset changed from 0 to 32
+  [C]'function void bar(int, S)' has some indirect sub-type changes:
+    parameter 1 of type 'struct S' has sub-type changes:
+      size changed from 32 to 64 bits
+      1 data member insertion:
+        'char S::m0', at offset 0 (in bits)
+      1 data member change:
+       'int S::m1' offset changed from 0 to 32
 
 
diff --git a/tests/data/test-diff-suppr/test8-redundant-fn-report-0.txt b/tests/data/test-diff-suppr/test8-redundant-fn-report-0.txt
new file mode 100644 (file)
index 0000000..5e86eb3
--- /dev/null
@@ -0,0 +1,12 @@
+Functions changes summary: 0 Removed, 1 Changed (1 filtered out), 0 Added function
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+1 function with some indirect sub-type change:
+
+  [C]'function void foo(S*)' has some indirect sub-type changes:
+    parameter 0 of type 'S*' has sub-type changes:
+      in pointed to type 'struct S':
+        size changed from 32 to 64 bits
+        1 data member insertion:
+          'char S::m1', at offset 32 (in bits)
+
diff --git a/tests/data/test-diff-suppr/test8-redundant-fn-report-1.txt b/tests/data/test-diff-suppr/test8-redundant-fn-report-1.txt
new file mode 100644 (file)
index 0000000..3b6471e
--- /dev/null
@@ -0,0 +1,15 @@
+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 bar(S&)' has some indirect sub-type changes:
+    parameter 0 of type 'S&' has sub-type changes:
+      in referenced type 'struct S':
+        size changed from 32 to 64 bits
+        1 data member insertion:
+          'char S::m1', at offset 32 (in bits)
+  [C]'function void foo(S*)' has some indirect sub-type changes:
+    parameter 0 of type 'S*' has sub-type changes:
+      pointed to type 'struct S' changed, as reported earlier
+
diff --git a/tests/data/test-diff-suppr/test8-redundant-fn-v0.cc b/tests/data/test-diff-suppr/test8-redundant-fn-v0.cc
new file mode 100644 (file)
index 0000000..498e11b
--- /dev/null
@@ -0,0 +1,16 @@
+// gcc -g -Wall -shared -o libtest21-redundant-fn-v0.so test21-redundant-fn-v0.cc 
+
+struct S
+{
+  int m0;
+};
+
+void
+foo(S*)
+{
+}
+
+void
+bar(S&)
+{
+}
diff --git a/tests/data/test-diff-suppr/test8-redundant-fn-v1.cc b/tests/data/test-diff-suppr/test8-redundant-fn-v1.cc
new file mode 100644 (file)
index 0000000..52890cc
--- /dev/null
@@ -0,0 +1,17 @@
+// gcc -g -Wall -shared -o libtest21-redundant-fn-v1.so test21-redundant-fn-v1.cc 
+
+struct S
+{
+  int m0;
+  char m1;
+};
+
+void
+foo(S*)
+{
+}
+
+void
+bar(S&)
+{
+}
diff --git a/tests/data/test-diff-suppr/test9-changed-parm-c-report-0.txt b/tests/data/test-diff-suppr/test9-changed-parm-c-report-0.txt
new file mode 100644 (file)
index 0000000..60ac22d
--- /dev/null
@@ -0,0 +1,11 @@
+Functions changes summary: 0 Removed, 1 Changed, 0 Added function
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+1 function with some indirect sub-type change:
+
+  [C]'function int foo(int)' has some indirect sub-type changes:
+    parameter 0 of type 'int' changed:
+      name changed from 'int' to 'char'
+      size changed from 32 to 8 bits
+      alignment changed from 32 to 8 bits
+
diff --git a/tests/data/test-diff-suppr/test9-changed-parm-c-report-1.txt b/tests/data/test-diff-suppr/test9-changed-parm-c-report-1.txt
new file mode 100644 (file)
index 0000000..60ac22d
--- /dev/null
@@ -0,0 +1,11 @@
+Functions changes summary: 0 Removed, 1 Changed, 0 Added function
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+1 function with some indirect sub-type change:
+
+  [C]'function int foo(int)' has some indirect sub-type changes:
+    parameter 0 of type 'int' changed:
+      name changed from 'int' to 'char'
+      size changed from 32 to 8 bits
+      alignment changed from 32 to 8 bits
+
diff --git a/tests/data/test-diff-suppr/test9-changed-parm-c-v0.c b/tests/data/test-diff-suppr/test9-changed-parm-c-v0.c
new file mode 100644 (file)
index 0000000..c457e9c
--- /dev/null
@@ -0,0 +1,7 @@
+/*
+  Compile with:
+     gcc -g -Wall -shared -o libtest9-changed-parm-c-v0.so test9-changed-parm-c-v0.c  */
+
+int
+foo(int a)
+{return a;}
diff --git a/tests/data/test-diff-suppr/test9-changed-parm-c-v1.c b/tests/data/test-diff-suppr/test9-changed-parm-c-v1.c
new file mode 100644 (file)
index 0000000..07aa55b
--- /dev/null
@@ -0,0 +1,7 @@
+/*
+  compile with:
+    gcc -g -Wall -shared -o libtest9-changed-parm-c-v1.so test9-changed-parm-c-v1.c 
+ */
+int
+foo(char a)
+{return a;}
index 2faaedd183b7d472fa2aa0f09969e28912d19c85..82cf85ea1e9f5135e10469aa1d5aeb8ec256ba4b 100644 (file)
@@ -188,6 +188,18 @@ InOutSpec in_out_specs[] =
     "data/test-diff-dwarf/test20-add-fn-parm-report-0.txt",
     "output/test-diff-dwarf/test20-add-fn-parm-report-0.txt"
   },
+  {
+    "data/test-diff-dwarf/libtest21-redundant-fn-v0.so",
+    "data/test-diff-dwarf/libtest21-redundant-fn-v1.so",
+    "data/test-diff-dwarf/test21-redundant-fn-report-0.txt",
+    "output/test-diff-dwarf/test21-redundant-fn-report-0.txt"
+  },
+  {
+    "data/test-diff-dwarf/libtest22-changed-parm-c-v0.so",
+    "data/test-diff-dwarf/libtest22-changed-parm-c-v1.so",
+    "data/test-diff-dwarf/test22-changed-parm-c-report-0.txt",
+    "output/test-diff-dwarf/test22-changed-parm-c-report-0.txt"
+  },
   // This should be the last entry
   {NULL, NULL, NULL, NULL}
 };
index 36f76f6863b17c1e948ecb886ec95ad91da04c9d..2bf36b988f52f03a312be0c381d0948f2965916a 100644 (file)
@@ -319,6 +319,38 @@ InOutSpec in_out_specs[] =
     "data/test-diff-suppr/test7-var-suppr-report-8.txt",
     "output/test-diff-suppr/test7-var-suppr-report-8.txt"
   },
+  {
+    "data/test-diff-suppr/libtest8-redundant-fn-v0.so",
+    "data/test-diff-suppr/libtest8-redundant-fn-v1.so",
+    "",
+    "--no-redundant",
+    "data/test-diff-suppr/test8-redundant-fn-report-0.txt",
+    "output/test-diff-suppr/test8-redundant-fn-report-0.txt"
+  },
+  {
+    "data/test-diff-suppr/libtest8-redundant-fn-v0.so",
+    "data/test-diff-suppr/libtest8-redundant-fn-v1.so",
+    "",
+    "--redundant",
+    "data/test-diff-suppr/test8-redundant-fn-report-1.txt",
+    "output/test-diff-suppr/test8-redundant-fn-report-1.txt"
+  },
+  {
+    "data/test-diff-suppr/libtest9-changed-parm-c-v0.so",
+    "data/test-diff-suppr/libtest9-changed-parm-c-v1.so",
+    "",
+    "--no-redundant",
+    "data/test-diff-suppr/test9-changed-parm-c-report-0.txt",
+    "output/test-diff-suppr/est9-changed-parm-c-report-0.txt"
+  },
+  {
+    "data/test-diff-suppr/libtest9-changed-parm-c-v0.so",
+    "data/test-diff-suppr/libtest9-changed-parm-c-v1.so",
+    "",
+    "--redundant",
+    "data/test-diff-suppr/test9-changed-parm-c-report-1.txt",
+    "output/test-diff-suppr/est9-changed-parm-c-report-1.txt"
+  },
   // This should be the last entry
   {NULL, NULL, NULL, NULL, NULL, NULL}
 };
This page took 0.170501 seconds and 5 git commands to generate.