mirror of
git://sourceware.org/git/libabigail.git
synced 2024-12-18 16:04:34 +00:00
Recognize cyclic diff tree nodes as being redundant
Okay I need to introduce some vocabulary here. Suppose we have the version 1 of a library named library-v1.so which source code is: struct S { int m0; struct S* m2; }; int foo(struct S* ptr) { return ptr; } And now suppose we have a version 2 of that library named library-v2.so which source code is modified so that a new data member is inserted into struct S: struct S { int m0; char m1; /* <--- a new data member is inserted here. */ struct S* m2; }; int foo(struct S* ptr) { return ptr; } struct S is said to be a cyclic type because it contains a (data) member which type refers to struct S itself, namely, the type of the data member S::m2 is struct S*, which refers to struct S. So, by analogy, the diff node tree that represents the changes of struct S is also said to be cyclic, for similar reasons: the diff node of the change of S::m2 refers to the diff node of the change of the type of S::m2, namely the diff node of struct S*, which refers to the diff node for the change of struct S itself. Now let's talk about redundancy. When walking the diff node tree of struct S in a depth-first manner, at some point, we look at the diff node for the data member S::m2, and we end up looking at the diff node of its type which is the diff node for struct S*; we keep walking and eventually we look the diff node of the change of the underlying type of struct S, which is the diff node of struct S, and hah! that is a redundant node because it's the first node that we visited when visiting the diff node of ... struct S! So the diff tree node for the change of struct S is not only a cyclic node, it's a redundant diff node as well, and its second occurrence is located at the point of appearance of data member S::m2. Hence the wording "cyclic redundant diff tree node". There! We have our vocabulary all set now. This patch enhances the code of the comparison engine so that a cyclic diff tree node is marked as redundant from the point of its second occurrence, onward. First the patch separates the notion of visiting a diff node from the notion of traversing it. Now traversing a diff node means visiting it and visiting its children nodes. So one can visit a node without traversing it, but one can not traverse a node without visiting it. So, when walking diff node trees, we need to avoid ending up in infinite loop in presence of cyclic nodes. This is why re-traversing a node that is already being traversed is forbidden by this patch, but visiting a node that is being visited is allowed. Before this patch, the notions of visiting and traversing were conflated in one and were not very clear; and one couldn't visit a node that was currently being visited. As a result, in presence of a cyclic node, its redundant nature wasn't being recognized, and so the diff tree node was not being flagged as being redundant. Diff reports were then cluttered by redundant references to changes involving cyclic types. * include/abg-comparison.h (enum visiting_kind): Rename enumerator DO_NOT_MARK_VISITED_NODES_AS_TRAVERSED into DO_NOT_MARK_VISITED_NODES_AS_VISITED. (diff_context::diff_has_been_visited): Rename diff_context::diff_has_been_traversed into this. (diff_context::mark_diff_as_visited): Rename diff_context::mark_diff_as_traversed into this. (diff_context::forget_visited_diffs): Rename diff_context::forget_traversed_diffs into this. (diff_context::forbid_visiting_a_node_twice): Rename diff_context::forbid_traversing_a_node_twice into this. (diff_context::visiting_a_node_twice_is_forbidden): Rename diff_context::traversing_a_node_twice_is_forbidden into this. (diff::is_traversing): Move this from protected to public. * src/abg-comparison.cc (diff_context::priv::visited_diff_nodes_): Rename diff_context::priv::traversed_diff_nodes_ into this. (diff_context::priv::forbid_visiting_a_node_twice_): Rename diff_context::priv::forbid_traversing_a_node_twice_ into this. (diff_context::priv::priv): Adjust. (diff_context::diff_has_been_visited): Rename diff_context::diff_has_been_traversed into this. Adjust. (diff_context::mark_diff_as_visited): Rename diff_context::mark_diff_as_traversed into this. Adjust. (diff_context::forget_visited_diffs): Rename diff_context::forget_traversed_diffs into this. Adjust. (diff_context::forbid_visiting_a_node_twice): Rename diff_context::forbid_traversing_a_node_twice into this. (diff_context::visiting_a_node_twice_is_forbidden): Rename diff_context::traversing_a_node_twice_is_forbidden into this. (diff_context::maybe_apply_filters): Adjust. (diff::end_traversing): Remove the 'mark_as_traversed' parameter of this. Remove the visited-marking code. (diff::traverse): This is the crux of the changes of this patch. Avoid traversing a node that is being traversed, but one can visit a node being visited. Also, traversing a node means visiting it and visiting its children nodes. (diff::is_filtered_out): Simplify logic for filtering redundant code. Basically all nodes that are redundant are filtered. All the complicated logic that was due when diff nodes were shared is not relevant anymore. (corpus_diff::priv::categorize_redundant_changed_sub_nodes) (propagate_categories, apply_suppressions) (diff_node_printer::diff_node_printer, print_diff_tree) (categorize_redundant_changed_sub_nodes) (clear_redundancy_categorization) (clear_redundancy_categorization): Adjust. (redundancy_marking_visitor::visit_begin): Adjust. Also, if the current diff node is already being traversed (that's a clyclic node) then mark it as redundant. * src/abg-comp-filter.cc (apply_filter): Adjust. * tests/data/test-diff-filter/test16-report-2.txt: New test input data. * tests/data/test-diff-filter/libtest25-cyclic-type-v{0,1}.so: New test input binaries. * tests/data/test-diff-filter/test25-cyclic-type-v{0,1}.cc: Source code for the test input binaries. * tests/data/test-diff-filter/test25-cyclic-type-report-0.txt: New test input data. * tests/data/test-diff-filter/test25-cyclic-type-report-1.txt: Likewise. * tests/test-diff-filter.cc (in_out_specs): Add the new test inputs above to the list of test input data over which to run this test harness. * tests/data/Makefile.am: Add the new test files above to source distribution. * tests/data/test-diff-filter/test16-report.txt: Adjust. * tests/data/test-diff-filter/test17-0-report.txt: Likewise. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
This commit is contained in:
parent
f3344623d3
commit
ddfb37ab17
@ -254,7 +254,7 @@ enum visiting_kind
|
||||
/// This says that the traversing code should not mark visited nodes
|
||||
/// as having been traversed. This is useful, for instance, for
|
||||
/// visitors which have debugging purposes.
|
||||
DO_NOT_MARK_VISITED_NODES_AS_TRAVERSED = 1 << 1
|
||||
DO_NOT_MARK_VISITED_NODES_AS_VISITED = 1 << 1
|
||||
};
|
||||
|
||||
visiting_kind
|
||||
@ -792,22 +792,22 @@ public:
|
||||
initialize_canonical_diff(const diff_sptr diff);
|
||||
|
||||
bool
|
||||
diff_has_been_traversed(const diff*) const;
|
||||
diff_has_been_visited(const diff*) const;
|
||||
|
||||
bool
|
||||
diff_has_been_traversed(const diff_sptr) const;
|
||||
diff_has_been_visited(const diff_sptr) const;
|
||||
|
||||
void
|
||||
mark_diff_as_traversed(const diff*);
|
||||
mark_diff_as_visited(const diff*);
|
||||
|
||||
void
|
||||
forget_traversed_diffs();
|
||||
forget_visited_diffs();
|
||||
|
||||
void
|
||||
forbid_traversing_a_node_twice(bool f);
|
||||
forbid_visiting_a_node_twice(bool f);
|
||||
|
||||
bool
|
||||
traversing_a_node_twice_is_forbidden() const;
|
||||
visiting_a_node_twice_is_forbidden() const;
|
||||
|
||||
diff_category
|
||||
get_allowed_category() const;
|
||||
@ -977,13 +977,8 @@ protected:
|
||||
void
|
||||
begin_traversing();
|
||||
|
||||
bool
|
||||
is_traversing() const;
|
||||
|
||||
void
|
||||
end_traversing(bool mark_as_traversed = true);
|
||||
|
||||
protected:
|
||||
end_traversing();
|
||||
|
||||
virtual void
|
||||
finish_diff_type();
|
||||
@ -1006,6 +1001,9 @@ public:
|
||||
|
||||
diff* get_canonical_diff() const;
|
||||
|
||||
bool
|
||||
is_traversing() const;
|
||||
|
||||
void
|
||||
append_child_node(diff_sptr);
|
||||
|
||||
|
@ -46,10 +46,10 @@ using std::tr1::dynamic_pointer_cast;
|
||||
void
|
||||
apply_filter(filter_base& filter, corpus_diff_sptr d)
|
||||
{
|
||||
bool s = d->context()->traversing_a_node_twice_is_forbidden();
|
||||
d->context()->forbid_traversing_a_node_twice(false);
|
||||
bool s = d->context()->visiting_a_node_twice_is_forbidden();
|
||||
d->context()->forbid_visiting_a_node_twice(false);
|
||||
d->traverse(filter);
|
||||
d->context()->forbid_traversing_a_node_twice(s);
|
||||
d->context()->forbid_visiting_a_node_twice(s);
|
||||
}
|
||||
|
||||
/// Walk a diff sub-tree and apply a filter to the nodes visted. The
|
||||
@ -62,10 +62,10 @@ apply_filter(filter_base& filter, corpus_diff_sptr d)
|
||||
void
|
||||
apply_filter(filter_base& filter, diff_sptr d)
|
||||
{
|
||||
bool s = d->context()->traversing_a_node_twice_is_forbidden();
|
||||
d->context()->forbid_traversing_a_node_twice(false);
|
||||
bool s = d->context()->visiting_a_node_twice_is_forbidden();
|
||||
d->context()->forbid_visiting_a_node_twice(false);
|
||||
d->traverse(filter);
|
||||
d->context()->forbid_traversing_a_node_twice(s);
|
||||
d->context()->forbid_visiting_a_node_twice(s);
|
||||
}
|
||||
|
||||
/// Walk a diff sub-tree and apply a filter to the nodes visted. The
|
||||
|
@ -2273,12 +2273,12 @@ struct diff_context::priv
|
||||
vector<diff_sptr> canonical_diffs;
|
||||
vector<filtering::filter_base_sptr> filters_;
|
||||
suppressions_type suppressions_;
|
||||
pointer_map traversed_diff_nodes_;
|
||||
pointer_map visited_diff_nodes_;
|
||||
corpus_sptr first_corpus_;
|
||||
corpus_sptr second_corpus_;
|
||||
ostream* default_output_stream_;
|
||||
ostream* error_output_stream_;
|
||||
bool forbid_traversing_a_node_twice_;
|
||||
bool forbid_visiting_a_node_twice_;
|
||||
bool show_stats_only_;
|
||||
bool show_soname_change_;
|
||||
bool show_architecture_change_;
|
||||
@ -2298,7 +2298,7 @@ struct diff_context::priv
|
||||
: allowed_category_(EVERYTHING_CATEGORY),
|
||||
default_output_stream_(),
|
||||
error_output_stream_(),
|
||||
forbid_traversing_a_node_twice_(true),
|
||||
forbid_visiting_a_node_twice_(true),
|
||||
show_stats_only_(false),
|
||||
show_soname_change_(true),
|
||||
show_architecture_change_(true),
|
||||
@ -2598,61 +2598,61 @@ diff_context::initialize_canonical_diff(const diff_sptr diff)
|
||||
///
|
||||
/// @param d the diff node to consider.
|
||||
bool
|
||||
diff_context::diff_has_been_traversed(const diff* d) const
|
||||
diff_context::diff_has_been_visited(const diff* d) const
|
||||
{
|
||||
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)
|
||||
!= priv_->traversed_diff_nodes_.end());
|
||||
return (priv_->visited_diff_nodes_.find(ptr_value)
|
||||
!= priv_->visited_diff_nodes_.end());
|
||||
}
|
||||
|
||||
/// Test if a diff node has been traversed.
|
||||
///
|
||||
/// @param d the diff node to consider.
|
||||
bool
|
||||
diff_context::diff_has_been_traversed(const diff_sptr d) const
|
||||
{return diff_has_been_traversed(d.get());}
|
||||
diff_context::diff_has_been_visited(const diff_sptr d) const
|
||||
{return diff_has_been_visited(d.get());}
|
||||
|
||||
/// 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
|
||||
/// Subsequent invocations of diff_has_been_visited() on the diff
|
||||
/// node will yield true.
|
||||
void
|
||||
diff_context::mark_diff_as_traversed(const diff* d)
|
||||
diff_context::mark_diff_as_visited(const diff* 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;
|
||||
priv_->visited_diff_nodes_[ptr_value] = true;
|
||||
}
|
||||
|
||||
/// Unmark all the diff nodes that were marked as being traversed.
|
||||
void
|
||||
diff_context::forget_traversed_diffs()
|
||||
{priv_->traversed_diff_nodes_.clear();}
|
||||
diff_context::forget_visited_diffs()
|
||||
{priv_->visited_diff_nodes_.clear();}
|
||||
|
||||
/// This sets a flag that, if it's true, then during the traversing of
|
||||
/// a diff nodes tree each node is traversed at most once.
|
||||
/// a diff nodes tree each node is visited at most once.
|
||||
///
|
||||
/// @param f if true then during the traversing of a diff nodes tree
|
||||
/// each node is traversed at most once.
|
||||
/// each node is visited at most once.
|
||||
void
|
||||
diff_context::forbid_traversing_a_node_twice(bool f)
|
||||
{priv_->forbid_traversing_a_node_twice_ = f;}
|
||||
diff_context::forbid_visiting_a_node_twice(bool f)
|
||||
{priv_->forbid_visiting_a_node_twice_ = f;}
|
||||
|
||||
/// Return a flag that, if true, then during the traversing of a diff
|
||||
/// nodes tree each node is traversed at most once.
|
||||
/// nodes tree each node is visited at most once.
|
||||
///
|
||||
/// @return the boolean flag.
|
||||
bool
|
||||
diff_context::traversing_a_node_twice_is_forbidden() const
|
||||
{return priv_->forbid_traversing_a_node_twice_;}
|
||||
diff_context::visiting_a_node_twice_is_forbidden() const
|
||||
{return priv_->forbid_visiting_a_node_twice_;}
|
||||
|
||||
/// Getter for the diff tree nodes filters to apply to diff sub-trees.
|
||||
///
|
||||
@ -2678,14 +2678,14 @@ diff_context::add_diff_filter(filtering::filter_base_sptr f)
|
||||
/// @param diff the diff sub-tree to apply the filters to.
|
||||
void
|
||||
diff_context::maybe_apply_filters(diff_sptr diff,
|
||||
bool traverse_nodes_once)
|
||||
bool visit_nodes_once)
|
||||
{
|
||||
if (get_allowed_category() == EVERYTHING_CATEGORY)
|
||||
return;
|
||||
|
||||
bool s = traversing_a_node_twice_is_forbidden();
|
||||
if (!traverse_nodes_once)
|
||||
forbid_traversing_a_node_twice(false);
|
||||
bool s = visiting_a_node_twice_is_forbidden();
|
||||
if (!visit_nodes_once)
|
||||
forbid_visiting_a_node_twice(false);
|
||||
|
||||
for (filtering::filters::const_iterator i = diff_filters().begin();
|
||||
i != diff_filters().end();
|
||||
@ -2695,8 +2695,8 @@ diff_context::maybe_apply_filters(diff_sptr diff,
|
||||
propagate_categories(diff);
|
||||
}
|
||||
|
||||
if (!traverse_nodes_once)
|
||||
forbid_traversing_a_node_twice(s);
|
||||
if (!visit_nodes_once)
|
||||
forbid_visiting_a_node_twice(s);
|
||||
}
|
||||
|
||||
/// Apply the diff filters to the diff nodes of a @ref corpus_diff
|
||||
@ -2709,11 +2709,11 @@ diff_context::maybe_apply_filters(diff_sptr diff,
|
||||
/// @param diff the corpus diff to apply the filters to.
|
||||
void
|
||||
diff_context::maybe_apply_filters(corpus_diff_sptr diff,
|
||||
bool traverse_nodes_once)
|
||||
bool visit_nodes_once)
|
||||
{
|
||||
bool s = traversing_a_node_twice_is_forbidden();
|
||||
if (!traverse_nodes_once)
|
||||
forbid_traversing_a_node_twice(false);
|
||||
bool s = visiting_a_node_twice_is_forbidden();
|
||||
if (!visit_nodes_once)
|
||||
forbid_visiting_a_node_twice(false);
|
||||
|
||||
for (filtering::filters::const_iterator i = diff_filters().begin();
|
||||
i != diff_filters().end();
|
||||
@ -2723,8 +2723,8 @@ diff_context::maybe_apply_filters(corpus_diff_sptr diff,
|
||||
propagate_categories(diff);
|
||||
}
|
||||
|
||||
if (!traverse_nodes_once)
|
||||
forbid_traversing_a_node_twice(s);
|
||||
if (!visit_nodes_once)
|
||||
forbid_visiting_a_node_twice(s);
|
||||
}
|
||||
|
||||
/// Getter for the vector of suppressions that specify which diff node
|
||||
@ -3104,6 +3104,9 @@ 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.
|
||||
///
|
||||
/// Note that traversing a node means visiting it *and* visiting its
|
||||
/// children nodes.
|
||||
///
|
||||
/// The canonical node is marked as being traversed too.
|
||||
///
|
||||
/// These functions are called by the traversing code.
|
||||
@ -3118,6 +3121,9 @@ diff::begin_traversing()
|
||||
|
||||
/// Tell if a given node is being traversed or not.
|
||||
///
|
||||
/// Note that traversing a node means visiting it *and* visiting its
|
||||
/// children nodes.
|
||||
///
|
||||
/// It's the canonical node which is looked at, actually.
|
||||
///
|
||||
/// Please read the comments for the diff::begin_traversing() for mode
|
||||
@ -3134,25 +3140,18 @@ diff::is_traversing() const
|
||||
|
||||
/// Flag a given diff node as not being traversed anymore.
|
||||
///
|
||||
/// Note that traversing a node means visiting it *and* visiting its
|
||||
/// children nodes.
|
||||
///
|
||||
/// Please read the comments of the function diff::begin_traversing()
|
||||
/// for mode context.
|
||||
///
|
||||
/// @param mark_as_traversed if set to true mark the current @ref diff
|
||||
/// node has having been traversed. That way, subsequent calls to
|
||||
/// diff_context::diff_has_been_traversed() on the current instance of
|
||||
/// @ref diff will yield true.
|
||||
void
|
||||
diff::end_traversing(bool mark_as_traversed)
|
||||
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.
|
||||
if (mark_as_traversed)
|
||||
context()->mark_diff_as_traversed(this);
|
||||
}
|
||||
|
||||
/// Finish the building of a given kind of a diff tree node.
|
||||
@ -3286,6 +3285,12 @@ diff::reported_once() const
|
||||
|
||||
/// The generic traversing code that walks a given diff sub-tree.
|
||||
///
|
||||
/// Note that there is a difference between traversing a diff node and
|
||||
/// visiting it. Basically, traversing a diff node means visiting it
|
||||
/// and visiting its children nodes too. So one can visit a node
|
||||
/// without traversing it. But traversing a node without visiting it
|
||||
/// is not possible.
|
||||
///
|
||||
/// @param v the entity that visits each node of the diff sub-tree.
|
||||
///
|
||||
/// @return true to tell the caller that all of the sub-tree could be
|
||||
@ -3296,51 +3301,58 @@ diff::traverse(diff_node_visitor& v)
|
||||
{
|
||||
finish_diff_type();
|
||||
|
||||
if (context()->traversing_a_node_twice_is_forbidden()
|
||||
&& context()->diff_has_been_traversed(this))
|
||||
if (context()->visiting_a_node_twice_is_forbidden()
|
||||
&& context()->diff_has_been_visited(this))
|
||||
return true;
|
||||
|
||||
if (is_traversing())
|
||||
return true;
|
||||
|
||||
begin_traversing();
|
||||
v.visit_begin(this);
|
||||
|
||||
bool mark_visited_nodes_as_traversed =
|
||||
!(v.get_visiting_kind() & DO_NOT_MARK_VISITED_NODES_AS_TRAVERSED);
|
||||
!(v.get_visiting_kind() & DO_NOT_MARK_VISITED_NODES_AS_VISITED);
|
||||
|
||||
if (!v.visit(this, /*pre=*/true))
|
||||
{
|
||||
v.visit_end(this);
|
||||
end_traversing(mark_visited_nodes_as_traversed);
|
||||
if (mark_visited_nodes_as_traversed)
|
||||
context()->mark_diff_as_visited(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(v.get_visiting_kind() & SKIP_CHILDREN_VISITING_KIND))
|
||||
for (vector<diff_sptr>::const_iterator i = children_nodes().begin();
|
||||
i != children_nodes().end();
|
||||
++i)
|
||||
{
|
||||
if (!(*i)->traverse(v))
|
||||
{
|
||||
v.visit_end(this);
|
||||
end_traversing(mark_visited_nodes_as_traversed);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!(v.get_visiting_kind() & SKIP_CHILDREN_VISITING_KIND)
|
||||
&& !is_traversing())
|
||||
{
|
||||
begin_traversing();
|
||||
for (vector<diff_sptr>::const_iterator i = children_nodes().begin();
|
||||
i != children_nodes().end();
|
||||
++i)
|
||||
{
|
||||
if (!(*i)->traverse(v))
|
||||
{
|
||||
v.visit_end(this);
|
||||
if (mark_visited_nodes_as_traversed)
|
||||
context()->mark_diff_as_visited(this);
|
||||
end_traversing();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
end_traversing();
|
||||
}
|
||||
|
||||
if (!v.visit(this, /*pref=*/false))
|
||||
{
|
||||
v.visit_end(this);
|
||||
end_traversing(mark_visited_nodes_as_traversed);
|
||||
if (mark_visited_nodes_as_traversed)
|
||||
context()->mark_diff_as_visited(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
v.visit_end(this);
|
||||
end_traversing(mark_visited_nodes_as_traversed);
|
||||
if (mark_visited_nodes_as_traversed)
|
||||
context()->mark_diff_as_visited(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Sets a flag saying if a report has already been emitted for the
|
||||
/// current diff.
|
||||
///
|
||||
@ -3416,17 +3428,11 @@ diff::is_filtered_out() const
|
||||
if (get_category() & SUPPRESSED_CATEGORY)
|
||||
return true;
|
||||
|
||||
// We don't want to display redundant top-level function or variable
|
||||
// diff nodes, when the user asked to avoid seeing redundant diff
|
||||
// nodes.
|
||||
if ((dynamic_cast<const function_decl_diff*>(this)
|
||||
|| (dynamic_cast<const var_diff*>(this)
|
||||
// We are talking about top-level variables diff nodes, not
|
||||
// member variables diff nodes.
|
||||
&& !is_member_decl(first_subject())))
|
||||
&& !context()->show_redundant_changes())
|
||||
if (get_category() & REDUNDANT_CATEGORY)
|
||||
return true;
|
||||
// We don't want to display redundant diff nodes, when the user
|
||||
// asked to avoid seeing redundant diff nodes.
|
||||
if (!context()->show_redundant_changes()
|
||||
&& (get_category() & REDUNDANT_CATEGORY))
|
||||
return true;
|
||||
|
||||
if (get_category() == NO_CHANGE_CATEGORY)
|
||||
return false;
|
||||
@ -10467,7 +10473,7 @@ corpus_diff::priv::categorize_redundant_changed_sub_nodes()
|
||||
{
|
||||
diff_sptr diff;
|
||||
|
||||
ctxt_->forget_traversed_diffs();
|
||||
ctxt_->forget_visited_diffs();
|
||||
for (function_decl_diff_sptrs_type::const_iterator i =
|
||||
changed_fns_.begin();
|
||||
i!= changed_fns_.end();
|
||||
@ -11802,10 +11808,10 @@ void
|
||||
propagate_categories(diff* diff_tree)
|
||||
{
|
||||
category_propagation_visitor v;
|
||||
bool s = diff_tree->context()->traversing_a_node_twice_is_forbidden();
|
||||
diff_tree->context()->forbid_traversing_a_node_twice(false);
|
||||
bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
|
||||
diff_tree->context()->forbid_visiting_a_node_twice(false);
|
||||
diff_tree->traverse(v);
|
||||
diff_tree->context()->forbid_traversing_a_node_twice(s);
|
||||
diff_tree->context()->forbid_visiting_a_node_twice(s);
|
||||
}
|
||||
|
||||
/// Visit all the nodes of a given sub-tree. For each node that has a
|
||||
@ -11828,10 +11834,10 @@ void
|
||||
propagate_categories(corpus_diff* diff_tree)
|
||||
{
|
||||
category_propagation_visitor v;
|
||||
bool s = diff_tree->context()->traversing_a_node_twice_is_forbidden();
|
||||
diff_tree->context()->forbid_traversing_a_node_twice(false);
|
||||
bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
|
||||
diff_tree->context()->forbid_visiting_a_node_twice(false);
|
||||
diff_tree->traverse(v);
|
||||
diff_tree->context()->forbid_traversing_a_node_twice(s);
|
||||
diff_tree->context()->forbid_visiting_a_node_twice(s);
|
||||
}
|
||||
|
||||
/// Visit all the nodes of a given corpus tree. For each node that
|
||||
@ -11919,10 +11925,10 @@ void
|
||||
apply_suppressions(diff* diff_tree)
|
||||
{
|
||||
suppression_categorization_visitor v;
|
||||
bool s = diff_tree->context()->traversing_a_node_twice_is_forbidden();
|
||||
diff_tree->context()->forbid_traversing_a_node_twice(false);
|
||||
bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
|
||||
diff_tree->context()->forbid_visiting_a_node_twice(false);
|
||||
diff_tree->traverse(v);
|
||||
diff_tree->context()->forbid_traversing_a_node_twice(s);
|
||||
diff_tree->context()->forbid_visiting_a_node_twice(s);
|
||||
}
|
||||
|
||||
/// Walk a given diff-sub tree and appply the suppressions carried by
|
||||
@ -11945,10 +11951,10 @@ void
|
||||
apply_suppressions(const corpus_diff* diff_tree)
|
||||
{
|
||||
suppression_categorization_visitor v;
|
||||
bool s = diff_tree->context()->traversing_a_node_twice_is_forbidden();
|
||||
diff_tree->context()->forbid_traversing_a_node_twice(false);
|
||||
bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
|
||||
diff_tree->context()->forbid_visiting_a_node_twice(false);
|
||||
const_cast<corpus_diff*>(diff_tree)->traverse(v);
|
||||
diff_tree->context()->forbid_traversing_a_node_twice(s);
|
||||
diff_tree->context()->forbid_visiting_a_node_twice(s);
|
||||
}
|
||||
|
||||
/// Walk a diff tree and appply the suppressions carried by the
|
||||
@ -11984,7 +11990,7 @@ struct diff_node_printer : public diff_node_visitor
|
||||
}
|
||||
|
||||
diff_node_printer(ostream& out)
|
||||
: diff_node_visitor(DO_NOT_MARK_VISITED_NODES_AS_TRAVERSED),
|
||||
: diff_node_visitor(DO_NOT_MARK_VISITED_NODES_AS_VISITED),
|
||||
out_(out),
|
||||
level_(0)
|
||||
{}
|
||||
@ -12073,10 +12079,10 @@ void
|
||||
print_diff_tree(diff* diff_tree, ostream& out)
|
||||
{
|
||||
diff_node_printer p(out);
|
||||
bool s = diff_tree->context()->traversing_a_node_twice_is_forbidden();
|
||||
diff_tree->context()->forbid_traversing_a_node_twice(false);
|
||||
bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
|
||||
diff_tree->context()->forbid_visiting_a_node_twice(false);
|
||||
diff_tree->traverse(p);
|
||||
diff_tree->context()->forbid_traversing_a_node_twice(s);
|
||||
diff_tree->context()->forbid_visiting_a_node_twice(s);
|
||||
}
|
||||
|
||||
/// Emit a textual representation of a @ref corpus_diff tree to an
|
||||
@ -12091,10 +12097,10 @@ void
|
||||
print_diff_tree(corpus_diff* diff_tree, std::ostream& out)
|
||||
{
|
||||
diff_node_printer p(out);
|
||||
bool s = diff_tree->context()->traversing_a_node_twice_is_forbidden();
|
||||
diff_tree->context()->forbid_traversing_a_node_twice(false);
|
||||
bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
|
||||
diff_tree->context()->forbid_visiting_a_node_twice(false);
|
||||
diff_tree->traverse(p);
|
||||
diff_tree->context()->forbid_traversing_a_node_twice(s);
|
||||
diff_tree->context()->forbid_visiting_a_node_twice(s);
|
||||
}
|
||||
|
||||
/// Emit a textual representation of a @ref diff sub-tree to an
|
||||
@ -12146,7 +12152,9 @@ struct redundancy_marking_visitor : public diff_node_visitor
|
||||
{
|
||||
// A diff node that carries a change and that has been already
|
||||
// traversed elsewhere is considered redundant.
|
||||
if (d->context()->diff_has_been_traversed(d) && d->length())
|
||||
if ((d->context()->diff_has_been_visited(d)
|
||||
|| d->get_canonical_diff()->is_traversing())
|
||||
&& d->length())
|
||||
{
|
||||
// But if two diff nodes are redundant sibbling, do not
|
||||
// mark them as being redundant. This is to avoid marking
|
||||
@ -12299,10 +12307,10 @@ categorize_redundancy(diff* diff_tree)
|
||||
if (diff_tree->context()->show_redundant_changes())
|
||||
return;
|
||||
redundancy_marking_visitor v;
|
||||
bool s = diff_tree->context()->traversing_a_node_twice_is_forbidden();
|
||||
diff_tree->context()->forbid_traversing_a_node_twice(false);
|
||||
bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
|
||||
diff_tree->context()->forbid_visiting_a_node_twice(false);
|
||||
diff_tree->traverse(v);
|
||||
diff_tree->context()->forbid_traversing_a_node_twice(s);
|
||||
diff_tree->context()->forbid_visiting_a_node_twice(s);
|
||||
}
|
||||
|
||||
/// Walk a given @ref diff sub-tree to categorize each of the nodes
|
||||
@ -12321,11 +12329,11 @@ void
|
||||
categorize_redundancy(corpus_diff* diff_tree)
|
||||
{
|
||||
redundancy_marking_visitor v;
|
||||
diff_tree->context()->forget_traversed_diffs();
|
||||
bool s = diff_tree->context()->traversing_a_node_twice_is_forbidden();
|
||||
diff_tree->context()->forbid_traversing_a_node_twice(false);
|
||||
diff_tree->context()->forget_visited_diffs();
|
||||
bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
|
||||
diff_tree->context()->forbid_visiting_a_node_twice(false);
|
||||
diff_tree->traverse(v);
|
||||
diff_tree->context()->forbid_traversing_a_node_twice(s);
|
||||
diff_tree->context()->forbid_visiting_a_node_twice(s);
|
||||
}
|
||||
|
||||
/// Walk a given @ref corpus_diff tree to categorize each of the nodes
|
||||
@ -12346,11 +12354,11 @@ void
|
||||
clear_redundancy_categorization(diff* diff_tree)
|
||||
{
|
||||
redundancy_clearing_visitor v;
|
||||
bool s = diff_tree->context()->traversing_a_node_twice_is_forbidden();
|
||||
diff_tree->context()->forbid_traversing_a_node_twice(false);
|
||||
bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
|
||||
diff_tree->context()->forbid_visiting_a_node_twice(false);
|
||||
diff_tree->traverse(v);
|
||||
diff_tree->context()->forbid_traversing_a_node_twice(s);
|
||||
diff_tree->context()->forget_traversed_diffs();
|
||||
diff_tree->context()->forbid_visiting_a_node_twice(s);
|
||||
diff_tree->context()->forget_visited_diffs();
|
||||
}
|
||||
|
||||
/// Walk a given @ref diff sub-tree to clear the REDUNDANT_CATEGORY
|
||||
@ -12369,11 +12377,11 @@ void
|
||||
clear_redundancy_categorization(corpus_diff* diff_tree)
|
||||
{
|
||||
redundancy_clearing_visitor v;
|
||||
bool s = diff_tree->context()->traversing_a_node_twice_is_forbidden();
|
||||
diff_tree->context()->forbid_traversing_a_node_twice(false);
|
||||
bool s = diff_tree->context()->visiting_a_node_twice_is_forbidden();
|
||||
diff_tree->context()->forbid_visiting_a_node_twice(false);
|
||||
diff_tree->traverse(v);
|
||||
diff_tree->context()->forbid_traversing_a_node_twice(s);
|
||||
diff_tree->context()->forget_traversed_diffs();
|
||||
diff_tree->context()->forbid_visiting_a_node_twice(s);
|
||||
diff_tree->context()->forget_visited_diffs();
|
||||
}
|
||||
|
||||
/// Walk a given @ref corpus_diff tree to clear the REDUNDANT_CATEGORY
|
||||
|
@ -307,7 +307,8 @@ test-diff-filter/test16-v0.cc \
|
||||
test-diff-filter/test16-v1.cc \
|
||||
test-diff-filter/test16-v0.o \
|
||||
test-diff-filter/test16-v1.o \
|
||||
test-diff-filter/test16-report.txt \
|
||||
test-diff-filter/test16-report.txt \
|
||||
test-diff-filter/test16-report-2.txt \
|
||||
test-diff-filter/test17-v0.cc \
|
||||
test-diff-filter/test17-v1.cc \
|
||||
test-diff-filter/test17-v0.o \
|
||||
@ -354,6 +355,12 @@ test-diff-filter/test24-compatible-vars-report-0.txt \
|
||||
test-diff-filter/test24-compatible-vars-report-1.txt \
|
||||
test-diff-filter/test24-compatible-vars-v0.c \
|
||||
test-diff-filter/test24-compatible-vars-v1.c \
|
||||
test-diff-filter/libtest25-cyclic-type-v0.so \
|
||||
test-diff-filter/libtest25-cyclic-type-v1.so \
|
||||
test-diff-filter/test25-cyclic-type-report-0.txt \
|
||||
test-diff-filter/test25-cyclic-type-report-1.txt \
|
||||
test-diff-filter/test25-cyclic-type-v0.cc \
|
||||
test-diff-filter/test25-cyclic-type-v1.cc \
|
||||
\
|
||||
test-diff-suppr/test0-type-suppr-v0.cc \
|
||||
test-diff-suppr/test0-type-suppr-v1.cc \
|
||||
|
BIN
tests/data/test-diff-filter/libtest25-cyclic-type-v0.so
Executable file
BIN
tests/data/test-diff-filter/libtest25-cyclic-type-v0.so
Executable file
Binary file not shown.
BIN
tests/data/test-diff-filter/libtest25-cyclic-type-v1.so
Executable file
BIN
tests/data/test-diff-filter/libtest25-cyclic-type-v1.so
Executable file
Binary file not shown.
17
tests/data/test-diff-filter/test16-report-2.txt
Normal file
17
tests/data/test-diff-filter/test16-report-2.txt
Normal file
@ -0,0 +1,17 @@
|
||||
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 void foo(S&)' has some indirect sub-type changes:
|
||||
parameter 0 of type 'S&' has sub-type changes:
|
||||
in referenced type 'struct S':
|
||||
size changed from 64 to 128 bits
|
||||
1 data member insertion:
|
||||
'int S::m0', at offset 0 (in bits)
|
||||
1 data member change:
|
||||
'S* S::m2' offset changed from 0 to 64
|
||||
and its type 'S*' changed:
|
||||
pointed to type 'struct S' changed; details are being reported
|
||||
|
||||
|
@ -11,7 +11,5 @@ Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
|
||||
'int S::m0', at offset 0 (in bits)
|
||||
1 data member change:
|
||||
'S* S::m2' offset changed from 0 to 64
|
||||
and its type 'S*' changed:
|
||||
pointed to type 'struct S' changed; details are being reported
|
||||
|
||||
|
||||
|
@ -11,7 +11,5 @@ Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
|
||||
'int S::m0', at offset 0 (in bits)
|
||||
1 data member change:
|
||||
'S* S::m2' offset changed from 0 to 64
|
||||
and its type 'S*' changed:
|
||||
pointed to type 'struct S' changed; details are being reported
|
||||
|
||||
|
||||
|
13
tests/data/test-diff-filter/test25-cyclic-type-report-0.txt
Normal file
13
tests/data/test-diff-filter/test25-cyclic-type-report-0.txt
Normal file
@ -0,0 +1,13 @@
|
||||
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 void foo(S&)' has some indirect sub-type changes:
|
||||
parameter 0 of type 'S&' has sub-type changes:
|
||||
in referenced type 'struct S':
|
||||
1 data member insertion:
|
||||
'char S::m1', at offset 32 (in bits)
|
||||
no data member change (1 filtered);
|
||||
|
||||
|
15
tests/data/test-diff-filter/test25-cyclic-type-report-1.txt
Normal file
15
tests/data/test-diff-filter/test25-cyclic-type-report-1.txt
Normal file
@ -0,0 +1,15 @@
|
||||
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 void foo(S&)' has some indirect sub-type changes:
|
||||
parameter 0 of type 'S&' has sub-type changes:
|
||||
in referenced type 'struct S':
|
||||
1 data member insertion:
|
||||
'char S::m1', at offset 32 (in bits)
|
||||
1 data member change:
|
||||
type of 'S* S::m2' changed:
|
||||
pointed to type 'struct S' changed; details are being reported
|
||||
|
||||
|
13
tests/data/test-diff-filter/test25-cyclic-type-v0.cc
Normal file
13
tests/data/test-diff-filter/test25-cyclic-type-v0.cc
Normal file
@ -0,0 +1,13 @@
|
||||
// Compile with:
|
||||
// g++ -g -shared -o libtest25-cyclic-type-v0.so test25-cyclic-type-v0.cc
|
||||
|
||||
struct S
|
||||
{
|
||||
int m0;
|
||||
S* m2;
|
||||
};
|
||||
|
||||
void
|
||||
foo(S&)
|
||||
{
|
||||
}
|
14
tests/data/test-diff-filter/test25-cyclic-type-v1.cc
Normal file
14
tests/data/test-diff-filter/test25-cyclic-type-v1.cc
Normal file
@ -0,0 +1,14 @@
|
||||
// Compile with:
|
||||
// g++ -g -shared -o libtest25-cyclic-type-v1.so test25-cyclic-type-v1.cc
|
||||
|
||||
struct S
|
||||
{
|
||||
int m0;
|
||||
char m1;
|
||||
S* m2;
|
||||
};
|
||||
|
||||
void
|
||||
foo(S&)
|
||||
{
|
||||
}
|
@ -194,6 +194,13 @@ InOutSpec in_out_specs[] =
|
||||
"data/test-diff-filter/test16-report.txt",
|
||||
"output/test-diff-filter/test16-report.txt",
|
||||
},
|
||||
{
|
||||
"data/test-diff-filter/test16-v0.o",
|
||||
"data/test-diff-filter/test16-v1.o",
|
||||
"--redundant",
|
||||
"data/test-diff-filter/test16-report-2.txt",
|
||||
"output/test-diff-filter/test16-report-2.txt",
|
||||
},
|
||||
{
|
||||
"data/test-diff-filter/test17-v0.o",
|
||||
"data/test-diff-filter/test17-v1.o",
|
||||
@ -292,6 +299,20 @@ InOutSpec in_out_specs[] =
|
||||
"data/test-diff-filter/test24-compatible-vars-report-1.txt ",
|
||||
"output/test-diff-filter/test24-compatible-vars-report-1.txt ",
|
||||
},
|
||||
{
|
||||
"data/test-diff-filter/libtest25-cyclic-type-v0.so",
|
||||
"data/test-diff-filter/libtest25-cyclic-type-v1.so",
|
||||
"",
|
||||
"data/test-diff-filter/test25-cyclic-type-report-0.txt ",
|
||||
"output/test-diff-filter/test25-cyclic-type-report-0.txt "
|
||||
},
|
||||
{
|
||||
"data/test-diff-filter/libtest25-cyclic-type-v0.so",
|
||||
"data/test-diff-filter/libtest25-cyclic-type-v1.so",
|
||||
"--redundant",
|
||||
"data/test-diff-filter/test25-cyclic-type-report-1.txt ",
|
||||
"output/test-diff-filter/test25-cyclic-type-report-1.txt "
|
||||
},
|
||||
// This should be the last entry
|
||||
{NULL, NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user