From 96ac630832ab42dbae2abd1ebc030cd417f151ce Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Fri, 10 May 2019 20:01:03 -0400
Subject: [PATCH 41/54] FIXME: save diagnostics until the end

---
 gcc/analyzer/impl-4.cc | 183 +++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 163 insertions(+), 20 deletions(-)

diff --git a/gcc/analyzer/impl-4.cc b/gcc/analyzer/impl-4.cc
index 3879af3..b11c09e 100644
--- a/gcc/analyzer/impl-4.cc
+++ b/gcc/analyzer/impl-4.cc
@@ -371,7 +371,7 @@ public:
     return program_point (NULL, NULL, 0, PK_DELETED, call_string ());
   }
 
-  bool on_edge (const exploded_graph &eg,
+  bool on_edge (exploded_graph &eg,
 		const superedge *succ);
 
 //private:
@@ -683,7 +683,7 @@ public:
   program_state prune_for_point (exploded_graph &eg,
 				 const program_point &point) const;
 
-  bool on_edge (const exploded_graph &eg,
+  bool on_edge (exploded_graph &eg,
 		const exploded_node &enode,
 		const superedge *succ);
 
@@ -741,8 +741,8 @@ class exploded_node : public dnode
   void dump_dot (graphviz_out *gv) const FINAL OVERRIDE;
   void dump_dot_id (pretty_printer *pp) const;
 
-  program_state on_stmt (const exploded_graph &eg) const;
-  bool on_edge (const exploded_graph &eg,
+  program_state on_stmt (exploded_graph &eg) const;
+  bool on_edge (exploded_graph &eg,
 		const superedge *succ,
 		program_point *next_point,
 		program_state *next_state) const;
@@ -759,7 +759,7 @@ class exploded_node : public dnode
 		      const program_state &old_state,
 		      program_state *new_state) const;
 
-  void detect_leaks (const exploded_graph &eg) const;
+  void detect_leaks (exploded_graph &eg) const;
 
   const program_point &get_point () const { return m_ps.m_point; }
   const supernode *get_supernode () const
@@ -869,6 +869,50 @@ struct eg_hashmap_traits
   }
 };
 
+/* FIXME.  */
+
+class saved_diagnostic
+{
+public:
+  saved_diagnostic (const state_machine &sm,
+		    const exploded_node *enode,
+		    const supernode *node, const gimple *stmt,
+		    stmt_finder *stmt_finder,
+		    tree var, state_machine::state_t state,
+		    pending_diagnostic *d);
+  ~saved_diagnostic ();
+
+  void emit (const exploded_graph &eg) const;
+
+private:
+  const state_machine &m_sm;
+  const exploded_node *m_enode;
+  const supernode *m_node;
+  const gimple *m_stmt;
+  stmt_finder *m_stmt_finder;
+  tree m_var;
+  state_machine::state_t m_state;
+  pending_diagnostic *m_d;
+};
+
+/* FIXME.  */
+
+class diagnostic_manager
+{
+public:
+  void add_diagnostic (const state_machine &sm,
+		       const exploded_node *enode,
+		       const supernode *node, const gimple *stmt,
+		       stmt_finder *finder,
+		       tree var, state_machine::state_t state,
+		       pending_diagnostic *d);
+
+  void emit_saved_diagnostics (const exploded_graph &eg);
+
+private:
+  auto_delete_vec<saved_diagnostic> m_saved_diagnostics;
+};
+
 /* An exploded_graph is a directed graph of unique <point, state> pairs.
    It also has a worklist of nodes that are waiting for their successors
    to be added to the graph.  */
@@ -898,16 +942,29 @@ public:
   void add_edge (exploded_node *src, exploded_node *dest,
 		 const superedge *sedge);
 
+  void save_diagnostic (const state_machine &sm,
+			const exploded_node *enode,
+			const supernode *node, const gimple *stmt,
+			stmt_finder *finder,
+			tree var, state_machine::state_t state,
+			pending_diagnostic *d);
+
   void emit_diagnostic (const state_machine &sm,
 			const exploded_node *enode,
 			const supernode *node, const gimple *stmt,
 			stmt_finder *finder,
 			tree var, state_machine::state_t state,
 			pending_diagnostic *d) const;
+
   void prune_path (checker4_path *path,
 		   const state_machine &sm,
 		   tree var, state_machine::state_t state) const;
 
+  diagnostic_manager &get_diagnostic_manager ()
+  {
+    return m_diagnostic_manager;
+  }
+
   stats *get_global_stats () { return &m_global_stats; }
   stats *get_or_create_function_stats (function *fn);
   void log_stats () const;
@@ -918,11 +975,9 @@ private:
   const supergraph &m_sg;
 
   /* Map from point/state to exploded node.
-     I couldn't get hash_map to properly clean up its keys, so
-     we store point_and_state pointers as keys, rather than
-     point_and_state, using the value from within
-     the exploded_node, with a custom hasher.
-   */
+     To avoid duplication we store point_and_state
+     *pointers* as keys, rather than point_and_state, using the
+     instance from within the exploded_node, with a custom hasher.  */
   typedef hash_map <const point_and_state *, exploded_node *,
 		    eg_hashmap_traits> map_t;
   map_t m_point_and_state_to_node;
@@ -935,6 +990,8 @@ private:
 
   const state_purge_map *const m_purge_map;
 
+  diagnostic_manager m_diagnostic_manager;
+
   const int m_verbosity;
 
   /* Stats.  */
@@ -991,6 +1048,8 @@ private:
 class stmt_finder
 {
 public:
+  virtual ~stmt_finder () {}
+  virtual stmt_finder *clone () const = 0;
   virtual const gimple *find_stmt (const exploded_path &epath) = 0;
 };
 
@@ -2033,7 +2092,7 @@ sm_state_map::purge (const state_machine &sm,
 class impl_sm_context : public sm_context, public log_user
 {
 public:
-  impl_sm_context (const exploded_graph &eg,
+  impl_sm_context (exploded_graph &eg,
 		   const state_machine &sm,
 		   const exploded_node *node,
 
@@ -2087,13 +2146,15 @@ public:
     state_machine::state_t current = m_old_smap.get_state (pv);
     if (state == current)
       {
-	m_eg.emit_diagnostic (m_sm, m_node, node, stmt, m_stmt_finder,
-			      var, state, d);
+	m_eg.get_diagnostic_manager ().add_diagnostic
+	  (m_sm, m_node, node, stmt, m_stmt_finder,
+	   var, state, d);
       }
-    delete d;
+    else
+      delete d;
   }
 
-  const exploded_graph &m_eg;
+  exploded_graph &m_eg;
   const state_machine &m_sm;
   const exploded_node *m_node;
   program_state *m_new_state;
@@ -2476,7 +2537,7 @@ fndecl_has_gimple_body_p (tree fndecl)
 /* FIXME.  */
 
 program_state
-exploded_node::on_stmt (const exploded_graph &eg) const
+exploded_node::on_stmt (exploded_graph &eg) const
 {
   const program_point &point = m_ps.m_point;
   const program_state &old_state = m_ps.m_state;
@@ -2692,7 +2753,7 @@ exploded_node::copy_sm_state (const exploded_graph &eg,
    Update NEXT_POINT accordingly (updating the call string).  */
 
 bool
-exploded_node::on_edge (const exploded_graph &eg,
+exploded_node::on_edge (exploded_graph &eg,
 			const superedge *succ,
 			program_point *next_point,
 			program_state *next_state) const
@@ -2765,6 +2826,11 @@ public:
   leak_stmt_finder (const exploded_graph &eg, path_var pv)
   : m_eg (eg), m_pv (pv) {}
 
+  stmt_finder *clone () const FINAL OVERRIDE
+  {
+    return new leak_stmt_finder (m_eg, m_pv);
+  }
+
   const gimple *find_stmt (const exploded_path &epath)
     FINAL OVERRIDE
   {
@@ -2848,7 +2914,7 @@ private:
    for top-level functions.  */
 
 void
-exploded_node::detect_leaks (const exploded_graph &eg) const
+exploded_node::detect_leaks (exploded_graph &eg) const
 {
   JIT_LOG_FUNC_1 (eg.get_logger (), "EN: %i", m_index);
 
@@ -2937,7 +3003,7 @@ exploded_node::detect_leaks (const exploded_graph &eg) const
    in the exploded graph.  */
 
 bool
-program_point::on_edge (const exploded_graph &eg,
+program_point::on_edge (exploded_graph &eg,
 			const superedge *succ)
 {
   JIT_LOG_FUNC (eg.get_logger ());
@@ -2999,7 +3065,7 @@ program_point::on_edge (const exploded_graph &eg,
 /* FIXME.  */
 
 bool
-program_state::on_edge (const exploded_graph &eg,
+program_state::on_edge (exploded_graph &eg,
 			const exploded_node &enode,
 			const superedge *succ)
 {
@@ -3238,6 +3304,80 @@ stats::dump (FILE *out) const
 
 ////////////////////////////////////////////////////////////////////////////
 
+/* class saved_diagnostic.  */
+
+/* FIXME.  */
+
+saved_diagnostic::saved_diagnostic (const state_machine &sm,
+				    const exploded_node *enode,
+				    const supernode *node, const gimple *stmt,
+				    stmt_finder *stmt_finder,
+				    tree var, state_machine::state_t state,
+				    pending_diagnostic *d)
+: m_sm (sm), m_enode (enode), m_node (node), m_stmt (stmt),
+ /* stmt_finder could be on-stack; we want our own copy that can
+    outlive that.  */
+  m_stmt_finder (stmt_finder ? stmt_finder->clone () : NULL),
+  m_var (var), m_state (state),
+  m_d (d)
+{
+}
+
+/* FIXME.  */
+
+saved_diagnostic::~saved_diagnostic ()
+{
+  delete m_stmt_finder;
+  delete m_d;
+}
+
+/* FIXME.  */
+
+void
+saved_diagnostic::emit (const exploded_graph &eg) const
+{
+  // FIXME: move body of it to this class?
+  eg.emit_diagnostic (m_sm, m_enode, m_node, m_stmt, m_stmt_finder,
+		      m_var, m_state, m_d);
+}
+
+////////////////////////////////////////////////////////////////////////////
+
+/* class diagnostic_manager.  */
+
+/* FIXME.  */
+
+void
+diagnostic_manager::add_diagnostic (const state_machine &sm,
+				    const exploded_node *enode,
+				    const supernode *node, const gimple *stmt,
+				    stmt_finder *finder,
+				    tree var, state_machine::state_t state,
+				    pending_diagnostic *d)
+{
+  // TODO: potentially do them directly, vs saved
+  // FIXME: stmt_finder might be on the stack!
+  saved_diagnostic *sd
+    = new saved_diagnostic (sm, enode, node, stmt, finder, var, state, d);
+  m_saved_diagnostics.safe_push (sd);
+}
+
+/* FIXME.  */
+
+void
+diagnostic_manager::emit_saved_diagnostics (const exploded_graph &eg)
+{
+  //JIT_LOG_SCOPE (get_logger ());
+  auto_client_timevar tv ("diagnostic_manager::emit_saved_diagnostics");
+
+  int i;
+  saved_diagnostic *sd;
+  FOR_EACH_VEC_ELT (m_saved_diagnostics, i, sd)
+    sd->emit (eg);
+}
+
+////////////////////////////////////////////////////////////////////////////
+
 /* exploded_graph's ctor.  */
 
 exploded_graph::exploded_graph (const supergraph &sg, logger *logger,
@@ -5022,6 +5162,9 @@ impl_run_checkers (logger *logger)
       free (filename);
     }
 
+  /* Now emit any saved diagnostics.  */
+  eg.get_diagnostic_manager ().emit_saved_diagnostics (eg);
+
   eg.log_stats ();
 
   delete purge_map;
-- 
1.8.5.3

