From 90a64590eb14966dffa8a253466dc5919cac10e4 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Fri, 26 Apr 2019 17:12:06 -0400
Subject: [PATCH 202/217] FIXME: impl-4: state-change events and final events

---
 gcc/analyzer/impl-4.cc | 95 +++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 70 insertions(+), 25 deletions(-)

diff --git a/gcc/analyzer/impl-4.cc b/gcc/analyzer/impl-4.cc
index 22e5769..132e300 100644
--- a/gcc/analyzer/impl-4.cc
+++ b/gcc/analyzer/impl-4.cc
@@ -266,6 +266,9 @@ namespace impl_4 {
 class sm_state_map
 {
 public:
+  typedef hash_map <path_var, state_machine::state_t> map_t;
+  typedef map_t::iterator iterator_t;
+
   sm_state_map *clone () const;
 
   void print (const state_machine &sm, pretty_printer *pp) const;
@@ -275,9 +278,12 @@ public:
   state_machine::state_t get_state (path_var pv) const;
   void set_state (path_var pv, state_machine::state_t state);
 
-private:
-  typedef hash_map <path_var, state_machine::state_t> map_t;
+  iterator_t begin () const { return m_var_to_state.begin (); }
+  iterator_t end () const { return m_var_to_state.end (); }
+
+  //private:
   map_t m_var_to_state;
+
 };
 #endif
 
@@ -392,6 +398,9 @@ class exploded_node : public dnode
   program_state on_edge (const exploded_graph &eg,
 			 const superedge *succ) const;
 
+  const program_point &get_point () const { return m_ps.m_point; }
+  const program_state &get_state () const { return m_ps.m_state; }
+
   point_and_state m_ps;
   /* FIXME: this is within the node since dump_dot is a vfunc
      In theory we could just pass this around instead.  */
@@ -430,7 +439,8 @@ public:
   void add_edge (exploded_node *src, exploded_node *dest,
 		 const superedge *sedge);
 
-  void emit_diagnostic (const exploded_node *enode,
+  void emit_diagnostic (const state_machine &sm,
+			const exploded_node *enode,
 			const supernode *node, const gimple *stmt,
 			tree var, state_machine::state_t state,
 			pending_diagnostic *d) const;
@@ -971,11 +981,11 @@ public:
   int get_verbosity () const;
 #endif
 
-  void add_final_event (const supernode *node, const gimple *stmt,
+  void add_final_event (const state_machine &sm,
+			const supernode *node, const gimple *stmt,
 			tree var, state_machine::state_t state,
 			pending_diagnostic *pd)
   {
-#if 0
     char *msg = NULL;
     label_text ev_desc = pd->describe_final_event (var, state);
     if (ev_desc.m_buffer)
@@ -983,7 +993,7 @@ public:
 	if (flag_analyzer_verbose_state_changes)
 	  {
 	    msg = print ("%s (%qE is in state %qs)", ev_desc.m_buffer,
-			 var, get_sm ().get_state_name (state));
+			 var, sm.get_state_name (state));
 	    ev_desc.maybe_free ();
 	  }
 	else
@@ -992,15 +1002,16 @@ public:
     else
       {
 	msg = print ("here (%qE is in state %qs)", var,
-		     get_sm ().get_state_name (state));
+		     sm.get_state_name (state));
 	// FIXME: ideally would show the full message here, too?
       }
     checker4_event *end_of_path
       = new warning_event (stmt->location,
-			   node->m_fun->decl, get_stack_depth (),
+			   node->m_fun->decl,
+			   // FIXME:
+			   0, /* get_stack_depth (), */
 			   msg);
     add_event (end_of_path);
-#endif
   }
 
   void prepare_for_emission (pending_diagnostic *pd)
@@ -1146,10 +1157,11 @@ class impl_sm_context : public sm_context, public log_user
 {
 public:
   impl_sm_context (const exploded_graph &eg,
+		   const state_machine &sm,
 		   const exploded_node *node,
 		   const sm_state_map &old_smap,
 		   sm_state_map *new_smap)
-  : log_user (eg.get_logger ()), m_eg (eg), m_node (node),
+  : log_user (eg.get_logger ()), m_eg (eg), m_sm (sm), m_node (node),
     m_old_smap (old_smap), m_new_smap (new_smap)
   {
   }
@@ -1175,12 +1187,13 @@ public:
     state_machine::state_t current = m_old_smap.get_state (pv);
     if (state == current)
       {
-	m_eg.emit_diagnostic (m_node, node, stmt, var, state, d);
+	m_eg.emit_diagnostic (m_sm, m_node, node, stmt, var, state, d);
       }
     delete d;
   }
 
   const exploded_graph &m_eg;
+  const state_machine &m_sm;
   const exploded_node *m_node;
   const sm_state_map &m_old_smap;
   sm_state_map *m_new_smap;
@@ -1389,10 +1402,10 @@ exploded_node::on_stmt (const exploded_graph &eg) const
   sm_state_map *smap;
   FOR_EACH_VEC_ELT (old_state.m_checker_states, i, smap)
     {
-      impl_sm_context ctxt (eg, this,
+      const state_machine &sm = m_ext_state.get_sm (i);
+      impl_sm_context ctxt (eg, sm, this,
 			    *old_state.m_checker_states[i],
 			    new_state.m_checker_states[i]);
-      const state_machine &sm = m_ext_state.get_sm (i);
       sm.on_stmt (&ctxt, point.m_supernode, point.get_stmt ());
     }
 
@@ -1414,10 +1427,10 @@ exploded_node::on_edge (const exploded_graph &eg,
   sm_state_map *smap;
   FOR_EACH_VEC_ELT (old_state.m_checker_states, i, smap)
     {
-      impl_sm_context ctxt (eg, this,
+      const state_machine &sm = m_ext_state.get_sm (i);
+      impl_sm_context ctxt (eg, sm, this,
 			    *old_state.m_checker_states[i],
 			    new_state.m_checker_states[i]);
-      const state_machine &sm = m_ext_state.get_sm (i);
       sm.on_edge (&ctxt, last_stmt, succ);
     }
 
@@ -1682,7 +1695,8 @@ exploded_graph::process_node (exploded_node *node)
 }
 
 void
-exploded_graph::emit_diagnostic (const exploded_node *enode,
+exploded_graph::emit_diagnostic (const state_machine &sm,
+				 const exploded_node *enode,
 				 const supernode *node, const gimple *stmt,
 				 tree var, state_machine::state_t state,
 				 pending_diagnostic *d) const
@@ -1716,7 +1730,7 @@ exploded_graph::emit_diagnostic (const exploded_node *enode,
 
   checker4_path emission_path;
   // TODO: build path
-  for (int i = 0; i < exploded_path.length (); i++)
+  for (unsigned i = 0; i < exploded_path.length (); i++)
     {
       const exploded_edge *eedge = exploded_path[i];
       if (get_logger ())
@@ -1724,9 +1738,9 @@ exploded_graph::emit_diagnostic (const exploded_node *enode,
 	     eedge->m_src->m_index,
 	     eedge->m_dest->m_index);
       const exploded_node *src_node = eedge->m_src;
-      const program_point &src_point = src_node->m_ps.m_point;
+      const program_point &src_point = src_node->get_point ();
       const exploded_node *dst_node = eedge->m_dest;
-      const program_point &dst_point = dst_node->m_ps.m_point;
+      const program_point &dst_point = dst_node->get_point ();
       switch (dst_point.m_kind)
 	{
 	default:
@@ -1745,7 +1759,6 @@ exploded_graph::emit_diagnostic (const exploded_node *enode,
 				      : UNKNOWN_LOCATION),
 				     src_point.m_supernode->m_fun->decl,
 				     0 /* FIXME: depth */ ));
-		  /* TODO: state changes due to edges.  */
 		}
 	    }
 	  // TODO: add function entry events
@@ -1765,14 +1778,46 @@ exploded_graph::emit_diagnostic (const exploded_node *enode,
 				  0 /* FIXME: depth */ ));
 	  break;
 	case PK_AFTER_STMT:
-	  /* TODO: state changes due to stmts.  */
 	  break;
 	}
+
+      /* Add state change events for the states that have changed.  */
+      const program_state &src_state = src_node->get_state ();
+      const program_state &dst_state = dst_node->get_state ();
+      const extrinsic_state &ext_state = m_ext_state;
+      gcc_assert (src_state.m_checker_states.length ()
+		  == ext_state.m_checkers.length ());
+      gcc_assert (dst_state.m_checker_states.length ()
+		  == ext_state.m_checkers.length ());
+      for (unsigned i = 0; i < ext_state.m_checkers.length (); i++)
+	{
+	  const state_machine &sm = ext_state.get_sm (i);
+	  const sm_state_map &src_smap = *src_state.m_checker_states[i];
+	  const sm_state_map &dst_smap = *dst_state.m_checker_states[i];
+	  for (sm_state_map::iterator_t iter = dst_smap.begin ();
+	       iter != dst_smap.end ();
+	       ++iter)
+	    {
+	      path_var pv = (*iter).first;
+	      state_machine::state_t dst_sm_val = (*iter).second;
+	      state_machine::state_t src_sm_val = src_smap.get_state (pv);
+	      if (dst_sm_val != src_sm_val)
+		emission_path.add_event
+		  (new state_change_event (dst_point.m_supernode,
+					   dst_point.get_stmt (),
+					   0, /* int stack_depth, */ //FIXME
+					   sm,
+					   pv.m_tree,
+					   src_sm_val,
+					   dst_sm_val,
+					   // FIXME:
+					   NULL_TREE)); /*tree origin */
+	    }
+	}
     }
-  /* TODO: state changes due to stmts.  */
 
   //m_engine->prune_path (&emission_path, var, state);
-  emission_path.add_final_event (node, stmt, var, state, d);
+  emission_path.add_final_event (sm, node, stmt, var, state, d);
   emission_path.prepare_for_emission (d);
 
   gcc_rich_location rich_loc (stmt->location);
@@ -1796,7 +1841,7 @@ shortest_paths::shortest_paths (const exploded_graph &eg)
   /* Dijkstra's algorithm.  */
   auto_vec<int> queue (eg.m_nodes.length ());
 
-  for (int i = 0; i < eg.m_nodes.length (); i++)
+  for (unsigned i = 0; i < eg.m_nodes.length (); i++)
     {
       m_dist.quick_push (INT_MAX);
       m_prev.quick_push (NULL);
@@ -1811,7 +1856,7 @@ shortest_paths::shortest_paths (const exploded_graph &eg)
       int idx_with_min_dist = -1;
       int idx_in_queue_with_min_dist = -1;
       int min_dist = INT_MAX;
-      for (int i = 0; i < queue.length (); i++)
+      for (unsigned i = 0; i < queue.length (); i++)
 	{
 	  int idx = queue[i];
 	  if (m_dist[queue[i]] < min_dist)
-- 
1.8.5.3

