From 9d6bc92432e779ec5c08b80c06ff07376599c17e Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Wed, 6 Mar 2019 13:05:18 -0500
Subject: [PATCH 66/87] FIXME: defer emission of diagnostics

---
 gcc/analyzer/engine.cc                 | 124 +++++++++++++++++++++++----------
 gcc/analyzer/hardcoded-state-machine.h |   1 +
 2 files changed, 87 insertions(+), 38 deletions(-)

diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc
index a094641..c75d58a 100644
--- a/gcc/analyzer/engine.cc
+++ b/gcc/analyzer/engine.cc
@@ -402,12 +402,37 @@ public:
 
 #include "constraints.h" // FIXME
 
+class candidate_diagnostic
+{
+public:
+  candidate_diagnostic (const supernode *node, const gimple *stmt,
+			tree var, state_machine::state_t state,
+			pending_diagnostic *pd, const diagnostic_path *path)
+  : m_node (node), m_stmt (stmt), m_var (var), m_state (state), m_pd (pd), 
+    m_path (*path)
+  {
+  }
+
+  ~candidate_diagnostic ()
+  {
+    delete m_pd;
+  }
+
+  const supernode *m_node;
+  const gimple *m_stmt;
+  tree m_var;
+  state_machine::state_t m_state;
+  pending_diagnostic *m_pd;
+  diagnostic_path m_path;
+};
+
 class engine : public log_user
 {
 public:
   engine (const supergraph &sg, const state_machine &sm,
 	  logger *logger)
   : log_user (logger), m_sg (sg), m_sm (sm), m_per_node_data (),
+    m_candidate_diagnostics (),
     m_num_traverse_calls (0),
     m_num_cache_hits (0),
     m_on_stmt_calls (0)
@@ -461,6 +486,9 @@ public:
   void detect_leaks (const supernode *node, const sm_instance &sm_inst,
 		     const backtrace &b, const path_state &ps);
 
+  void emit_candidate_diagnostics ();
+  void maybe_emit (const candidate_diagnostic &cd);
+
   const supergraph &m_sg;
 
   // FIXME: this implies one traversal per state machine; should we instead
@@ -470,6 +498,8 @@ public:
   // FIXME: should this be just a vec, instead (using the node indices)?
   hash_map <const supernode *, per_node_t *> m_per_node_data;
 
+  auto_delete_vec <candidate_diagnostic> m_candidate_diagnostics;
+
   int m_num_traverse_calls;
   int m_num_cache_hits;
   int m_on_stmt_calls;
@@ -681,7 +711,7 @@ public:
 		       pending_diagnostic *d) FINAL OVERRIDE
   {
     JIT_LOG_FUNC (m_engine->get_logger ());
-    gcc_assert (d);
+    gcc_assert (d); // take ownership
 
     var_state_t vs_from (var, state);
     if (!const_cast <sm_instance *> (m_old_sm_inst)->m_active_vars.m_set.contains (vs_from))
@@ -693,43 +723,11 @@ public:
 	return;
       }
 
-    gcc_rich_location rich_loc (stmt->location);
-#if 0
-    backtrace full_backtrace;
-    if (!make_full_backtrace (&full_backtrace))
-      {
-	if (m_engine->get_logger ())
-	  m_engine->log ("unable to make full backtrace in state %s; rejecting",
-			 m_engine->m_sm.get_state_name (state));
-	return;
-      }
-    diagnostic_path path;
-    make_path_from_backtrace (&path, m_engine, full_backtrace, stmt);
-#else
-    diagnostic_path path (*m_path);
-#endif
-    path.add_event (stmt->location,
-		    node->m_fun->decl, 0,/*state.get_stack_depth ()*/
-		    "here (%qE is in state %qs)", var,
-		    m_engine->m_sm.get_state_name (state));
-    // FIXME: ideally would show the message here, too?
-
-    rich_loc.set_path (&path);
-
-    /* Push/pop cfun to ensure we get "In function " announcements
-       from the diagnostics subsystem.  */
-    push_cfun (node->m_fun);
-    d->emit (&rich_loc);
-#if 0
-    va_list ap;
-    va_start (ap, fmt);
-    emit_diagnostic_valist (DK_WARNING, &rich_loc, m, 0, fmt,
-			    &ap);
-    va_end (ap);
-#endif
-    pop_cfun ();
-
-    delete d;
+    m_engine->log ("recording candidate diagnostic %i",
+		   m_engine->m_candidate_diagnostics.length ());
+    candidate_diagnostic *cd
+      = new candidate_diagnostic (node, stmt, var, state, d, m_path);
+    m_engine->m_candidate_diagnostics.safe_push (cd);
   }
 
 private:
@@ -1696,6 +1694,55 @@ engine::detect_leaks (const supernode *node, const sm_instance &sm_inst,
 
 /* FIXME.  */
 
+void
+engine::emit_candidate_diagnostics ()
+{
+  // TODO: maybe sort them first
+  int i;
+  candidate_diagnostic *cd;
+  FOR_EACH_VEC_ELT (m_candidate_diagnostics, i, cd)
+    maybe_emit (*cd);
+}
+
+/* FIXME.  */
+
+void
+engine::maybe_emit (const candidate_diagnostic &cd)
+{
+  // FIXME: for now, no filtering
+
+  gcc_rich_location rich_loc (cd.m_stmt->location);
+#if 0
+  backtrace full_backtrace;
+  if (!make_full_backtrace (&full_backtrace))
+    {
+      if (m_engine->get_logger ())
+	m_engine->log ("unable to make full backtrace in state %s; rejecting",
+		       m_engine->m_sm.get_state_name (state));
+      return;
+    }
+  diagnostic_path path;
+  make_path_from_backtrace (&path, m_engine, full_backtrace, stmt);
+#else
+  diagnostic_path path (cd.m_path);
+#endif
+  path.add_event (cd.m_stmt->location,
+		  cd.m_node->m_fun->decl, 0,/*state.get_stack_depth ()*/
+		  "here (%qE is in state %qs)", cd.m_var,
+		  m_sm.get_state_name (cd.m_state));
+  // FIXME: ideally would show the message here, too?
+
+  rich_loc.set_path (&path);
+
+  /* Push/pop cfun to ensure we get "In function " announcements
+     from the diagnostics subsystem.  */
+  push_cfun (cd.m_node->m_fun);
+  cd.m_pd->emit (&rich_loc);
+  pop_cfun ();
+}
+
+/* FIXME.  */
+
 class engine_annotator : public dot_annotator
 {
 public:
@@ -1877,6 +1924,7 @@ run_one_checker (const supergraph &sg, const state_machine &sm, logger *logger)
       e.dfs_traverse (sm_inst, b, ps,
 		      sg.get_node_for_function_entry (fun),
 		      NULL);
+      e.emit_candidate_diagnostics ();
     }
 
   if (1)
diff --git a/gcc/analyzer/hardcoded-state-machine.h b/gcc/analyzer/hardcoded-state-machine.h
index c109116..25bb697 100644
--- a/gcc/analyzer/hardcoded-state-machine.h
+++ b/gcc/analyzer/hardcoded-state-machine.h
@@ -71,6 +71,7 @@ class metadata : public diagnostic_metadata
 class pending_diagnostic
 {
  public:
+  virtual ~pending_diagnostic () {}
   virtual void emit (rich_location *) = 0;
 };
 
-- 
1.8.5.3

