]> sourceware.org Git - libabigail.git/commitdiff
Add a --dump-diff-tree to abidiff for debugging purposes
authorDodji Seketeli <dodji@redhat.com>
Sat, 27 Dec 2014 11:42:34 +0000 (12:42 +0100)
committerDodji Seketeli <dodji@redhat.com>
Sun, 28 Dec 2014 10:36:52 +0000 (11:36 +0100)
I have felt the need to emit a textual representation of the diff
nodes tree maintained by the comparison engine for changed functions
and variables.  This patch adds that functionality.

* include/abg-comparison.h (enum visiting_kind): Add new
DO_NOT_MARK_VISITED_NODES_AS_TRAVERSED enumerator.
(diff_context::{default_output_stream, error_output_stream,
dump_diff_tree}): Declare new accessors.
(diff::end_traversing): Take a new boolean flag.
(print_diff_tree): Add new overload for diff_sptr.
* src/abg-comparison.cc
(diff_context::priv::{default_output_stream_,
error_output_stream_, dump_diff_tree_}): New data members.
(priv::priv): Initialize them.
(diff_context::{default_output_stream_, error_output_stream_,
dump_diff_tree, dump_diff_tree}): Define new accessors.
(diff::end_traversing): Take a new flag that control whether or
not to mark the current diff node as having been traversed.
(diff::traverse): Take in account the visiting kind carried by the
visitor to determine if the visited node should be marked as being
traversed.
(corpus_diff::priv::maybe_dump_diff_tree): Define new member
function.
(corpus_diff::report): Call it.
(diff_node_printer::visit): Pretty print the diff node just once.
(print_diff_tree): Define a new overload for diff_sptr.
* tools/abidiff.cc (options::dump_diff_tree): New data member.
(options::options): Initialize it.
(display_usage): Add a help string for the new --dump-diff-tree
command line switch.
(parse_command_line): Parse the new --dump-diff-tree command line
switch.
(set_diff_context_from_opts): Set the diff context according to
the --dump-diff-tree presence.
* doc/manuals/abidiff.rst: Add a bullet point for the new
--dump-diff-tree command line switch.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
doc/manuals/abidiff.rst
include/abg-comparison.h
src/abg-comparison.cc
tools/abidiff.cc

index 1f8a8a7f5468667debf3b0cab3c03eccfcd9289c..1ae8ee54ebb9db71423b09ec026c4ca1b12b55dd 100644 (file)
@@ -192,6 +192,16 @@ Options
     redundant change is a change that has been displayed elsewhere in
     the report.  This option is switched on by default.
 
+  *  --dump-diff-tree
+
+    After the diff report, emit a textual representation of the diff
+    nodes tree used by the comparison engine to represent the changed
+    functions and variables.  That representation is emitted to the
+    error output for debugging purposes.  Note that this diff tree is
+    relevant only to functions and variables that have some sub-type
+    changes.  Added or removed functions and variables do not have any
+    diff nodes tree associated to them.
+
 Usage examples
 ==============
 
index 8d05a781dea75dc67e5944f214da89123969b1fd..5c6cd3a05fade6bba2cc3e9a211bcd14821f3751 100644 (file)
@@ -240,9 +240,15 @@ enum visiting_kind
   /// The default enumerator value of this enum.  It doesn't have any
   /// particular meaning yet.
   DEFAULT_VISITING_KIND = 0,
+
   /// This says that the traversing code should avoid visiting the
   /// children nodes of the current node being visited.
-  SKIP_CHILDREN_VISITING_KIND = 1
+  SKIP_CHILDREN_VISITING_KIND = 1,
+
+  /// This says that the traversing code should not mark visited nodes
+  /// as having been traversed.  This is useful, for instance, for
+  /// visitors which have debugging purposes.
+  DO_NOT_MARK_VISITED_NODES_AS_TRAVERSED = 1 << 1
 };
 
 visiting_kind
@@ -904,6 +910,24 @@ public:
   void
   show_added_symbols_unreferenced_by_debug_info(bool f);
 
+  void
+  default_output_stream(ostream*);
+
+  ostream*
+  default_output_stream();
+
+  void
+  error_output_stream(ostream*);
+
+  ostream*
+  error_output_stream();
+
+  bool
+  dump_diff_tree() const;
+
+  void
+  dump_diff_tree(bool f);
+
   friend class_diff_sptr
   compute_diff(const class_decl_sptr   first,
               const class_decl_sptr    second,
@@ -945,7 +969,7 @@ protected:
   is_traversing() const;
 
   void
-  end_traversing();
+  end_traversing(bool mark_as_traversed = true);
 
 protected:
 
@@ -2262,10 +2286,18 @@ protected:
 
 public:
 
+  /// Default constructor of the @ref diff_node_visitor type.
   diff_node_visitor()
     : visiting_kind_()
   {}
 
+  /// Constructor of the @ref diff_node_visitor type.
+  ///
+  /// @param k how the visiting has to be performed.
+  diff_node_visitor(visiting_kind k)
+    : visiting_kind_(k)
+  {}
+
   /// Getter for the visiting policy of the traversing code while
   /// invoking this visitor.
   ///
@@ -2384,6 +2416,10 @@ void
 print_diff_tree(corpus_diff* diff_tree,
                std::ostream&);
 
+void
+print_diff_tree(diff_sptr diff_tree,
+               std::ostream&);
+
 void
 print_diff_tree(corpus_diff_sptr diff_tree,
                std::ostream&);
index f97d8a68e41b87db10fbab47504648a4fd1758a0..12b3b09a7d6dfffe765674d185cc8635bc61696c 100644 (file)
@@ -2267,6 +2267,8 @@ struct diff_context::priv
   pointer_map                          traversed_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                                 show_stats_only_;
   bool                                 show_soname_change_;
@@ -2280,9 +2282,12 @@ struct diff_context::priv
   bool                                 show_redundant_changes_;
   bool                                 show_syms_unreferenced_by_di_;
   bool                                 show_added_syms_unreferenced_by_di_;
+  bool                                 dump_diff_tree_;
 
   priv()
     : allowed_category_(EVERYTHING_CATEGORY),
+      default_output_stream_(),
+      error_output_stream_(),
       forbid_traversing_a_node_twice_(true),
       show_stats_only_(false),
       show_soname_change_(true),
@@ -2295,7 +2300,8 @@ struct diff_context::priv
       show_linkage_names_(false),
       show_redundant_changes_(true),
       show_syms_unreferenced_by_di_(true),
-      show_added_syms_unreferenced_by_di_(true)
+      show_added_syms_unreferenced_by_di_(true),
+      dump_diff_tree_()
    {}
  };// end struct diff_context::priv
 
@@ -2907,6 +2913,58 @@ void
 diff_context::show_added_symbols_unreferenced_by_debug_info(bool f)
 {priv_->show_added_syms_unreferenced_by_di_ = f;}
 
+/// Setter for the default output stream used by code of the
+/// comparison engine.  By default the default output stream is a NULL
+/// pointer.
+///
+/// @param o a pointer to the default output stream.
+void
+diff_context::default_output_stream(ostream* o)
+{priv_->default_output_stream_ = o;}
+
+/// Getter for the default output stream used by code of the
+/// comparison engine.  By default the default output stream is a NULL
+/// pointer.
+///
+/// @return a pointer to the default output stream.
+ostream*
+diff_context::default_output_stream()
+{return priv_->default_output_stream_;}
+
+/// Setter for the errror output stream used by code of the comparison
+/// engine.  By default the error output stream is a NULL pointer.
+///
+/// @param o a pointer to the error output stream.
+void
+diff_context::error_output_stream(ostream* o)
+{priv_->error_output_stream_ = o;}
+
+/// Getter for the errror output stream used by code of the comparison
+/// engine.  By default the error output stream is a NULL pointer.
+///
+/// @return a pointer to the error output stream.
+ostream*
+diff_context::error_output_stream()
+{return priv_->error_output_stream_;}
+
+/// Test if the comparison engine should dump the diff tree for the
+/// changed functions and variables it has.
+///
+/// @return true if after the comparison, the engine should dump the
+/// diff tree for the changed functions and variables it has.
+bool
+diff_context::dump_diff_tree() const
+{return priv_->dump_diff_tree_;}
+
+/// Set if the comparison engine should dump the diff tree for the
+/// changed functions and variables it has.
+///
+/// @param f true if after the comparison, the engine should dump the
+/// diff tree for the changed functions and variables it has.
+void
+diff_context::dump_diff_tree(bool f)
+{priv_->dump_diff_tree_ = f;}
+
 // </diff_context stuff>
 
 // <diff stuff>
@@ -3026,9 +3084,14 @@ diff::is_traversing() const
 /// Flag a given diff node as not being traversed anymore.
 ///
 /// Please read the comments of the function diff::begin_traversing()
-/// for mode context;
+/// 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()
+diff::end_traversing(bool mark_as_traversed)
 {
   assert(is_traversing());
   if (priv_->canonical_diff_)
@@ -3037,7 +3100,8 @@ diff::end_traversing()
 
   // 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);
+  if (mark_as_traversed)
+    context()->mark_diff_as_traversed(this);
 }
 
 /// Finish the building of a given kind of a diff tree node.
@@ -3185,10 +3249,13 @@ diff::traverse(diff_node_visitor& v)
   begin_traversing();
   v.visit_begin(this);
 
+  bool mark_visited_nodes_as_traversed =
+    !(v.get_visiting_kind() & DO_NOT_MARK_VISITED_NODES_AS_TRAVERSED);
+
   if (!v.visit(this, /*pre=*/true))
     {
       v.visit_end(this);
-      end_traversing();
+      end_traversing(mark_visited_nodes_as_traversed);
       return false;
     }
 
@@ -3200,7 +3267,7 @@ diff::traverse(diff_node_visitor& v)
        if (!(*i)->traverse(v))
          {
            v.visit_end(this);
-           end_traversing();
+           end_traversing(mark_visited_nodes_as_traversed);
            return false;
          }
       }
@@ -3208,12 +3275,12 @@ diff::traverse(diff_node_visitor& v)
   if (!v.visit(this, /*pref=*/false))
     {
       v.visit_end(this);
-      end_traversing();
+      end_traversing(mark_visited_nodes_as_traversed);
       return false;
     }
 
   v.visit_end(this);
-  end_traversing();
+  end_traversing(mark_visited_nodes_as_traversed);
 
   return true;
 }
@@ -9839,6 +9906,8 @@ struct corpus_diff::priv
   void
   clear_redundancy_categorization();
 
+  void
+  maybe_dump_diff_tree();
 }; // end corpus::priv
 
 /// Tests if the lookup tables are empty.
@@ -10354,6 +10423,44 @@ corpus_diff::priv::clear_redundancy_categorization()
     }
 }
 
+/// If the user asked to dump the diff tree node (for changed
+/// variables and functions) on the error output stream, then just do
+/// that.
+///
+/// This function is used for debugging purposes.
+void
+corpus_diff::priv::maybe_dump_diff_tree()
+{
+  if (!ctxt_->dump_diff_tree()
+      || ctxt_->error_output_stream() == 0)
+    return;
+
+  if (!changed_fns_.empty())
+    {
+      *ctxt_->error_output_stream() << "changed functions diff tree: \n\n";
+      for (string_function_decl_diff_sptr_map::const_iterator i =
+            changed_fns_.begin();
+          i != changed_fns_.end();
+          ++i)
+       {
+         diff_sptr d = i->second;
+         print_diff_tree(d, *ctxt_->error_output_stream());
+       }
+    }
+
+  if (!changed_vars_.empty())
+    {
+      *ctxt_->error_output_stream() << "\nchanged variables diff tree: \n\n";
+      for (string_var_diff_sptr_map::const_iterator i = changed_vars_.begin();
+          i != changed_vars_.end();
+          ++i)
+       {
+         diff_sptr d = i->second;
+         print_diff_tree(d, *ctxt_->error_output_stream());
+       }
+    }
+}
+
 /// Populate the vector of children node of the @ref corpus_diff type.
 ///
 /// The children node can then later be retrieved using
@@ -11203,6 +11310,7 @@ corpus_diff::report(ostream& out, const string& indent) const
        out << '\n';
     }
 
+  priv_->maybe_dump_diff_tree();
 }
 
 /// Traverse the diff sub-tree under the current instance corpus_diff.
@@ -11733,7 +11841,8 @@ struct diff_node_printer : public diff_node_visitor
   unsigned level_;
 
   diff_node_printer(ostream& out)
-    : out_(out),
+    : diff_node_visitor(DO_NOT_MARK_VISITED_NODES_AS_TRAVERSED),
+      out_(out),
       level_(0)
   {}
 
@@ -11762,8 +11871,14 @@ struct diff_node_printer : public diff_node_visitor
   }
 
   virtual bool
-  visit(diff* d, bool)
+  visit(diff* d, bool pre)
   {
+    if (!pre)
+      // We are post-visiting the diff node D.  Which means, we have
+      // printed a pretty representation for it already.  So do
+      // nothing now.
+      return true;
+
     // indent
     for (unsigned i = 0; i < level_; ++i)
       out_ << ' ';
@@ -11776,8 +11891,14 @@ struct diff_node_printer : public diff_node_visitor
   }
 
   virtual bool
-  visit(corpus_diff* d, bool)
+  visit(corpus_diff* d, bool pre)
   {
+    if (!pre)
+      // We are post-visiting the diff node D.  Which means, we have
+      // printed a pretty representation for it already.  So do
+      // nothing now.
+      return true;
+
     // indent
     for (unsigned i = 0; i < level_; ++i)
       out_ << ' ';
@@ -11825,6 +11946,19 @@ print_diff_tree(corpus_diff* diff_tree, std::ostream& out)
   diff_tree->context()->forbid_traversing_a_node_twice(s);
 }
 
+/// Emit a textual representation of a @ref diff sub-tree to an
+/// output stream.
+///
+/// @param diff_tree the sub-tree to emit the textual representation
+/// for.
+///
+/// @param out the output stream to emit the textual representation
+/// for @p diff_tree to.
+void
+print_diff_tree(diff_sptr diff_tree,
+               std::ostream& o)
+{print_diff_tree(diff_tree.get(), o);}
+
 /// Emit a textual representation of a @ref corpus_diff tree to an
 /// output stream.
 ///
index 36c55750fa9ffcb89ef65f34005d38bdced4bc05..4bae1b4bc401b7a428d1b559ee9ca36f201d2ab3 100644 (file)
@@ -76,6 +76,7 @@ struct options
   bool                 show_harmless_changes;
   bool                 show_redundant_changes;
   bool                 show_symbols_not_referenced_by_debug_info;
+  bool                 dump_diff_tree;
   shared_ptr<char>     di_root_path1;
   shared_ptr<char>     di_root_path2;
 
@@ -96,7 +97,8 @@ struct options
       show_harmful_changes(true),
       show_harmless_changes(false),
       show_redundant_changes(false),
-      show_symbols_not_referenced_by_debug_info(true)
+      show_symbols_not_referenced_by_debug_info(true),
+      dump_diff_tree()
   {}
 };//end struct options;
 
@@ -132,6 +134,8 @@ display_usage(const string& prog_name, ostream& out)
       << " --redundant  display redundant changes\n"
       << " --no-redundant  do not display redundant changes "
          "(this is the default)\n"
+      << " --dump-diff-tree  emit a debug dump of the internal diff tree to "
+         "the error output stream\n"
       << " --help  display this message\n";
 }
 
@@ -317,6 +321,8 @@ parse_command_line(int argc, char* argv[], options& opts)
        opts.show_redundant_changes = true;
       else if (!strcmp(argv[i], "--no-redundant"))
        opts.show_redundant_changes = false;
+      else if (!strcmp(argv[i], "--dump-diff-tree"))
+       opts.dump_diff_tree = true;
       else
        return false;
     }
@@ -372,6 +378,8 @@ static void
 set_diff_context_from_opts(diff_context_sptr ctxt,
                           options& opts)
 {
+  ctxt->default_output_stream(&cout);
+  ctxt->error_output_stream(&cerr);
   ctxt->show_stats_only(opts.show_stats_only);
   ctxt->show_deleted_fns(opts.show_all_fns || opts.show_deleted_fns);
   ctxt->show_changed_fns(opts.show_all_fns || opts.show_changed_fns);
@@ -404,6 +412,8 @@ set_diff_context_from_opts(diff_context_sptr ctxt,
        ++i)
     read_suppressions(*i, supprs);
   ctxt->add_suppressions(supprs);
+
+  ctxt->dump_diff_tree(opts.dump_diff_tree);
 }
 
 /// Set the regex patterns describing the functions to drop from the
This page took 0.0612740000000001 seconds and 5 git commands to generate.