From 6d5ec3ca470e417aa6e0a66c88a522a3eb39fd09 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Fri, 19 Feb 2021 14:50:33 -0500
Subject: [PATCH 18/23] FIXME: sort the sets after we have best candidates and
 stmt_finders are run

---
 gcc/analyzer/diagnostic-manager.cc | 171 ++++++++++++++++++-----------
 gcc/analyzer/diagnostic-manager.h  |  28 ++++-
 2 files changed, 130 insertions(+), 69 deletions(-)

diff --git a/gcc/analyzer/diagnostic-manager.cc b/gcc/analyzer/diagnostic-manager.cc
index 59e481b73ee..0eec1f27133 100644
--- a/gcc/analyzer/diagnostic-manager.cc
+++ b/gcc/analyzer/diagnostic-manager.cc
@@ -253,12 +253,19 @@ dedupe_key::get_location () const
 /* FIXME.  */
 
 dedupe_set::dedupe_set (const dedupe_key &key)
-: m_key (key)
+: m_key (key), m_best_sd (NULL), m_best_epath (NULL)
 {
 }
 
 /* FIXME.  */
 
+dedupe_set::~dedupe_set ()
+{
+  delete m_best_epath;
+}
+
+/* FIXME.  */
+
 void
 dedupe_set::add_diagnostic (const exploded_node *enode,
 			    stmt_finder *finder,
@@ -271,52 +278,25 @@ dedupe_set::add_diagnostic (const exploded_node *enode,
   m_saved_diagnostics.safe_push (sd);
 }
 
-/* A qsort comparator for use by FIXME
-   to sort them into location_t order.  */
-
-int
-dedupe_set::comparator (const void *p1, const void *p2)
-{
-  const dedupe_set *ps1 = *(const dedupe_set * const *)p1;
-  const dedupe_set *ps2 = *(const dedupe_set * const *)p2;
-
-  const dedupe_key *pk1 = &ps1->m_key;
-  const dedupe_key *pk2 = &ps2->m_key;
-
-  location_t loc1 = pk1->get_location ();
-  location_t loc2 = pk2->get_location ();
-
-  if (int cmp = linemap_compare_locations (line_table, loc2, loc1))
-    return cmp;
-#if 0
-  if (int cmp = ((int)pk1->m_sd.get_epath_length ()
-		 - (int)pk2->m_sd.get_epath_length ()))
-    return cmp;
-#endif
-  if (int cmp = strcmp (pk1->m_d->get_kind (),
-			pk2->m_d->get_kind ()))
-    return cmp;
-  return 0;
-}
-
-/* Emit the simplest diagnostic within each set.  */
+/* Determine the simplest diagnostic within this set, and store it in
+   m_best_sd and m_best_epath.  */
 
 void
-dedupe_set::emit_best (diagnostic_manager *dm,
-		       const exploded_graph &eg,
-		       const void */*shortest_exploded_paths &*/hack)
+dedupe_set::calc_best_candidate (diagnostic_manager *dm,
+				 const exploded_graph &eg,
+				 const void */*shortest_exploded_paths &*/hack)
 {
   const shortest_exploded_paths &sp = *(const shortest_exploded_paths *)hack;
 
+  gcc_assert (m_best_sd == NULL);
+  gcc_assert (m_best_epath == NULL);
+
   logger *logger = dm->get_logger ();
   LOG_SCOPE (logger);
 
   /* Find the best candidate in this set.  */
-  saved_diagnostic *best_sd = NULL;
-  exploded_path *best_epath = NULL;
   unsigned i;
   saved_diagnostic *iter_sd;
-  //auto_vec<exploded_path> paths (m_saved_diagnostics.length ()); // FIXME
   FOR_EACH_VEC_ELT (m_saved_diagnostics, i, iter_sd)
     {
       exploded_path *iter_epath
@@ -378,17 +358,15 @@ dedupe_set::emit_best (diagnostic_manager *dm,
 
       /* If we get here, then it's either feasible, or we're accepting
 	 it as infeasible.  */
-      if (best_epath)
+      if (m_best_epath)
 	{
-	  if (iter_epath->length () < best_epath->length ())
+	  if (iter_epath->length () < m_best_epath->length ())
 	    {
 	      /* We've got a shorter path.  */
 	      if (logger)
 		logger->log ("length %i is better than existing length %i",
-			     iter_epath->length (), best_epath->length ());
-	      best_sd = iter_sd;
-	      delete best_epath;
-	      best_epath = iter_epath;
+			     iter_epath->length (), m_best_epath->length ());
+	      set_best (iter_sd, iter_epath);
 	  }
 	else
 	  /* We haven't beaten the current best candidate;
@@ -397,7 +375,7 @@ dedupe_set::emit_best (diagnostic_manager *dm,
 	    if (logger)
 	      logger->log ("length %i isn't better than existing length %i;"
 			   " dropping this candidate",
-			   iter_epath->length (), best_epath->length ());
+			   iter_epath->length (), m_best_epath->length ());
 	    delete iter_epath;
 	  }
 	}
@@ -405,21 +383,78 @@ dedupe_set::emit_best (diagnostic_manager *dm,
 	{
 	  if (logger)
 	    logger->log ("first path for this dedupe_set");
-	  best_sd = iter_sd;
-	  best_epath = iter_epath;
+	  set_best (iter_sd, iter_epath);
 	}
     }
 
+  /* Support deferring the choice of stmt until after an emission path has
+     been built, using an optional stmt_finder.  */
+  if (m_key.m_stmt == NULL)
+    if (m_best_sd)
+      {
+	gcc_assert (m_best_epath);
+	gcc_assert (m_best_sd->m_stmt_finder);
+	m_key.m_stmt = m_best_sd->m_stmt_finder->find_stmt (*m_best_epath);
+      }
+  /* Any set for which we have a best candidate should now have an m_stmt.  */
+  gcc_assert (m_key.m_stmt != NULL || m_best_sd == NULL);
+}
+
+/* Set SD and EPATH as the best diagnostic (so far) within this set.
+   Borrow SD; take ownership of EPATH.  */
+
+void
+dedupe_set::set_best (const saved_diagnostic *sd, exploded_path *epath)
+{
+  delete m_best_epath;
+  m_best_sd = sd;
+  m_best_epath = epath;
+}
+
+/* A qsort comparator for use by FIXME
+   to sort them into location_t order.  */
+
+int
+dedupe_set::comparator (const void *p1, const void *p2)
+{
+  const dedupe_set *ps1 = *(const dedupe_set * const *)p1;
+  const dedupe_set *ps2 = *(const dedupe_set * const *)p2;
+
+  const dedupe_key *pk1 = &ps1->m_key;
+  const dedupe_key *pk2 = &ps2->m_key;
+
+  location_t loc1 = pk1->get_location ();
+  location_t loc2 = pk2->get_location ();
+
+  if (int cmp = linemap_compare_locations (line_table, loc2, loc1))
+    return cmp;
+  if (int cmp = ((int)ps1->get_best_epath ()->length ()
+		 - (int)ps2->get_best_epath ()->length ()))
+    return cmp;
+  if (int cmp = strcmp (pk1->m_d->get_kind (),
+			pk2->m_d->get_kind ()))
+    return cmp;
+  return 0;
+}
+
+/* Emit the best diagnostic within this set, if any.  */
+
+void
+dedupe_set::emit_best (diagnostic_manager *dm,
+		       const exploded_graph &eg) const
+{
+  logger *logger = dm->get_logger ();
+  LOG_SCOPE (logger);
+
   /* Emit the best candidate, if any.  */
-  if (best_sd)
+  if (m_best_sd)
     {
-      gcc_assert (best_epath);
+      gcc_assert (m_best_epath);
       dm->emit_saved_diagnostic (eg,
-				 *best_sd,
-				 *best_epath,
+				 *m_best_sd,
+				 *m_best_epath,
 				 m_key.m_stmt, // FIXME: or stmt finder?
 				 m_saved_diagnostics.length ()); // or -1 ?
-      delete best_epath;
     }
 }
 
@@ -791,27 +826,37 @@ diagnostic_manager::emit_saved_diagnostics (const exploded_graph &eg)
     return;
 #endif
 
-  auto_vec<dedupe_set *> sets (m_dedupe_map.elements ());
-  for (dedupe_map_t::iterator iter = m_dedupe_map.begin ();
-       iter != m_dedupe_map.end (); ++iter)
-    sets.quick_push ((*iter).second);
-
-  log ("# dedupe sets: %i", sets.length ());
+  log ("# dedupe sets: %li", m_dedupe_map.elements ());
+  // FIXME
 
-  if (sets.length () == 0)
+  /* Don't bother computing shortest paths if there are no diagnostics
+     to emit.  */
+  if (m_dedupe_map.elements () == 0)
     return;
 
-  /* Sort into a good emission order.  */
-  sets.qsort (dedupe_set::comparator);
-
   /* Compute the shortest_paths once, sharing it between all diagnostics.  */
   shortest_exploded_paths sp (eg, eg.get_origin ());
 
-  /* Emit the best candidate for each key.  */
+  /* Determine the best saved_diagnostic in each dedupe_set.  */
+  for (dedupe_map_t::iterator iter = m_dedupe_map.begin ();
+       iter != m_dedupe_map.end (); ++iter)
+    (*iter).second->calc_best_candidate (this, eg, &sp);
+
+  /* Sort into a good emission order.
+     This needs to happen after the best candidates (and their exploded_paths)
+     are determined, since the sort order uses the location_t, and any cases
+     that need to use a stmt_finder need an exploded_path to work on.  */
+  auto_vec<dedupe_set *> sorted_sets (m_dedupe_map.elements ());
+  for (dedupe_map_t::iterator iter = m_dedupe_map.begin ();
+       iter != m_dedupe_map.end (); ++iter)
+    sorted_sets.quick_push ((*iter).second);
+  sorted_sets.qsort (dedupe_set::comparator);
+
+  /* Emit the sorted best candidates for each dedupe_set.  */
   int i;
   dedupe_set *set;
-  FOR_EACH_VEC_ELT (sets, i, set)
-    set->emit_best (this, eg, &sp);
+  FOR_EACH_VEC_ELT (sorted_sets, i, set)
+    set->emit_best (this, eg);
 
   // FIXME: update internal docs if necessary
 }
diff --git a/gcc/analyzer/diagnostic-manager.h b/gcc/analyzer/diagnostic-manager.h
index 39e82422517..57986a2fb34 100644
--- a/gcc/analyzer/diagnostic-manager.h
+++ b/gcc/analyzer/diagnostic-manager.h
@@ -131,28 +131,42 @@ private:
   feasibility_problem *m_problem;
 };
 
-/* FIXME.
-   An equivalence class of saved_diagnostics.  */
+/* An equivalence class of saved_diagnostics, for those that are
+   sufficiently similar.
+   We only want to emit the simplest diagnostic within each such set .  */
 
 class dedupe_set
 {
 public:
   dedupe_set (const dedupe_key &key);
+  ~dedupe_set ();
+
   void add_diagnostic (const exploded_node *enode,
 		       stmt_finder *finder,
 		       const svalue *sval,
 		       pending_diagnostic *d);
   const dedupe_key *get_key () const { return &m_key; }
 
+  void calc_best_candidate (diagnostic_manager *dm,
+			    const exploded_graph &eg,
+			    const void */*shortest_exploded_paths &*/sp);
+
   static int comparator (const void *p1, const void *p2);
 
   void emit_best (diagnostic_manager *dm,
-		  const exploded_graph &eg,
-		  const void */*shortest_exploded_paths &*/sp);
+		  const exploded_graph &eg) const;
+
+  // FIXME: add dump methods
+
+  const exploded_path *get_best_epath () const { return m_best_epath; }
 
 private:
+  void set_best (const saved_diagnostic *sd, exploded_path *epath);
+
   dedupe_key m_key;
   auto_delete_vec<saved_diagnostic> m_saved_diagnostics;
+  const saved_diagnostic *m_best_sd; /* borrowed.  */
+  exploded_path *m_best_epath; /* owned.  */
 };
 
 /* Traits for use by diagnostic_manager::m_dedupe_map.  */
@@ -242,6 +256,8 @@ public:
 			      const gimple *stmt,
 			      int num_dupes);
 
+  // FIXME: add dump methods
+
 #if 0
   unsigned get_num_diagnostics () const
   {
@@ -301,8 +317,8 @@ private:
   engine *m_eng;
 
   /* This maps from each dedupe_key to a dedupe_set.  */
-  typedef hash_map<const dedupe_key *, dedupe_set *,
-		   dedupe_hash_map_traits> dedupe_map_t;
+  typedef ordered_hash_map<const dedupe_key *, dedupe_set *,
+			   dedupe_hash_map_traits> dedupe_map_t;
   dedupe_map_t m_dedupe_map;
 
   const int m_verbosity;
-- 
2.26.2

