From 3e58c90ea3493dfa3ebecb53d514ef6d8a3c0b85 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Wed, 8 Jun 2016 15:00:31 -0400
Subject: [PATCH 13/22] FIXME: more on consolidating fixits

---
 gcc/diagnostic.c          | 18 ----------
 gcc/gcc-rich-location.h   |  5 ---
 libcpp/include/line-map.h | 22 ++++++++++--
 libcpp/line-map.c         | 88 ++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 106 insertions(+), 27 deletions(-)

diff --git a/gcc/diagnostic.c b/gcc/diagnostic.c
index 930e7aa..856e7fb 100644
--- a/gcc/diagnostic.c
+++ b/gcc/diagnostic.c
@@ -670,23 +670,6 @@ diagnostic_pop_diagnostics (diagnostic_context *context, location_t where)
 /* FIXME.  */
 
 static void
-consolidate_fixits (rich_location *richloc)
-{
-#if 0
-  for (unsigned i = 1; i < richloc->get_num_fixit_hints (); i++)
-    {
-      const fixit_hint *prev = richloc->get_fixit_hint (i - 1);
-      const fixit_hint *next = richloc->get_fixit_hint (i);
-      source_location start_loc = hint->get_start_loc ();
-      expanded_location start_exploc = expand_location (start_loc);
-      fprintf (out, "fix-it:");
-      print_escaped_string (out, start_exploc.file);
-#endif
-}
-
-/* FIXME.  */
-
-static void
 print_escaped_string (FILE *out, const char *text)
 {
   fputc ('"', out);
@@ -928,7 +911,6 @@ diagnostic_report_diagnostic (diagnostic_context *context,
 	  free (option_text);
 	}
     }
-  consolidate_fixits (diagnostic->richloc);
   diagnostic->message.x_data = &diagnostic->x_data;
   diagnostic->x_data = NULL;
   pp_format (context->printer, &diagnostic->message);
diff --git a/gcc/gcc-rich-location.h b/gcc/gcc-rich-location.h
index 9c8a790..0599904 100644
--- a/gcc/gcc-rich-location.h
+++ b/gcc/gcc-rich-location.h
@@ -31,11 +31,6 @@ class gcc_rich_location : public rich_location
   gcc_rich_location (source_location loc) :
     rich_location (line_table, loc) {}
 
-  /* Constructing from a source_range.  */
-  gcc_rich_location (source_range src_range) :
-    rich_location (src_range) {}
-
-
   /* Methods for adding ranges via gcc entities.  */
   void
   add_expr (tree expr);
diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h
index 416419c..67b33de 100644
--- a/libcpp/include/line-map.h
+++ b/libcpp/include/line-map.h
@@ -1347,9 +1347,6 @@ class rich_location
   /* Constructing from a location.  */
   rich_location (line_maps *set, source_location loc);
 
-  /* Constructing from a source_range.  */
-  rich_location (source_range src_range);
-
   /* Destructor.  */
   ~rich_location ();
 
@@ -1391,12 +1388,14 @@ class rich_location
 
   unsigned int get_num_fixit_hints () const { return m_num_fixit_hints; }
   fixit_hint *get_fixit_hint (int idx) const { return m_fixit_hints[idx]; }
+  fixit_hint *get_last_fixit_hint () const;
 
 public:
   static const int MAX_RANGES = 3;
   static const int MAX_FIXIT_HINTS = 2;
 
 protected:
+  line_maps *m_line_table;
   unsigned int m_num_ranges;
   location_range m_ranges[MAX_RANGES];
 
@@ -1420,6 +1419,11 @@ public:
   virtual bool affects_line_p (const char *file, int line) = 0;
   virtual source_location get_start_loc () const = 0;
   virtual bool maybe_get_end_loc (source_location *out) const = 0;
+
+  /* Vfuncs for consolidating successor fixits.  */
+  virtual bool maybe_append_replace (line_maps *set,
+				     source_range src_range,
+				     const char *new_content) = 0;
 };
 
 class fixit_insert : public fixit_hint
@@ -1432,6 +1436,9 @@ class fixit_insert : public fixit_hint
   bool affects_line_p (const char *file, int line);
   source_location get_start_loc () const { return m_where; }
   bool maybe_get_end_loc (source_location *) const { return false; }
+  bool maybe_append_replace (line_maps *set,
+			     source_range src_range,
+			     const char *new_content);
 
   source_location get_location () const { return m_where; }
   const char *get_string () const { return m_bytes; }
@@ -1457,6 +1464,9 @@ class fixit_remove : public fixit_hint
     *out = m_src_range.m_finish;
     return true;
   }
+  bool maybe_append_replace (line_maps *set,
+			     source_range src_range,
+			     const char *new_content);
 
   source_range get_range () const { return m_src_range; }
 
@@ -1479,11 +1489,17 @@ class fixit_replace : public fixit_hint
     *out = m_src_range.m_finish;
     return true;
   }
+  bool maybe_append_replace (source_range src_range,
+			     const char *new_content);
 
   source_range get_range () const { return m_src_range; }
   const char *get_string () const { return m_bytes; }
   size_t get_length () const { return m_len; }
 
+  bool maybe_append_replace (line_maps *set,
+			     source_range src_range,
+			     const char *new_content);
+
  private:
   source_range m_src_range;
   char *m_bytes;
diff --git a/libcpp/line-map.c b/libcpp/line-map.c
index 2e61895..668505f 100644
--- a/libcpp/line-map.c
+++ b/libcpp/line-map.c
@@ -1971,7 +1971,8 @@ source_range::intersects_line_p (const char *file, int line) const
 
 /* Construct a rich_location with location LOC as its initial range.  */
 
-rich_location::rich_location (line_maps */*set*/, source_location loc) :
+rich_location::rich_location (line_maps *set, source_location loc) :
+  m_line_table (set),
   m_num_ranges (0),
   m_column_override (0),
   m_have_expanded_location (false),
@@ -2102,6 +2103,36 @@ rich_location::add_fixit_remove (source_range src_range)
   m_fixit_hints[m_num_fixit_hints++] = new fixit_remove (src_range);
 }
 
+/* FIXME.  */
+
+static bool
+column_before_p (line_maps *set, source_location a, source_location b)
+{
+  if (IS_ADHOC_LOC (a))
+    a = get_location_from_adhoc_loc (set, a);
+  if (IS_ADHOC_LOC (b))
+    b = get_location_from_adhoc_loc (set, b);
+
+  /* They must both be in ordinary maps.  */
+  const struct line_map *linemap_a = linemap_lookup (set, a);
+  if (linemap_macro_expansion_map_p (linemap_a))
+    return false;
+  const struct line_map *linemap_b = linemap_lookup (set, b);
+  if (linemap_macro_expansion_map_p (linemap_b))
+    return false;
+
+  /* To be on the same line, they must be in the same ordinary map.  */
+  if (linemap_a != linemap_b)
+    return false;
+
+  linenum_type column_a
+    = SOURCE_COLUMN (linemap_check_ordinary (linemap_a), a);
+  linenum_type column_b
+    = SOURCE_COLUMN (linemap_check_ordinary (linemap_b), b);
+
+  return column_b == column_a + 1;
+}
+
 /* Add a fixit-hint, suggesting replacement of the content at
    SRC_RANGE with NEW_CONTENT.  */
 
@@ -2110,10 +2141,30 @@ rich_location::add_fixit_replace (source_range src_range,
 				  const char *new_content)
 {
   linemap_assert (m_num_fixit_hints < MAX_FIXIT_HINTS);
+
+  /* Consolidate neighboring fixits.  */
+  fixit_hint *prev = get_last_fixit_hint ();
+  if (m_num_fixit_hints > 0)
+    {
+      if (prev->maybe_append_replace (m_line_table, src_range, new_content))
+	return;
+    }
+
   m_fixit_hints[m_num_fixit_hints++]
     = new fixit_replace (src_range, new_content);
 }
 
+/* FIXME.  */
+
+fixit_hint *
+rich_location::get_last_fixit_hint () const
+{
+  if (m_num_fixit_hints > 0)
+    return m_fixit_hints[m_num_fixit_hints - 1];
+  else
+    return NULL;
+}
+
 /* class fixit_insert.  */
 
 fixit_insert::fixit_insert (source_location where,
@@ -2142,6 +2193,14 @@ fixit_insert::affects_line_p (const char *file, int line)
   return false;
 }
 
+/* FIXME.  */
+
+bool
+fixit_insert::maybe_append_replace (line_maps *, source_range, const char *)
+{
+  return false;
+}
+
 /* class fixit_remove.  */
 
 fixit_remove::fixit_remove (source_range src_range)
@@ -2157,6 +2216,14 @@ fixit_remove::affects_line_p (const char *file, int line)
   return m_src_range.intersects_line_p (file, line);
 }
 
+/* FIXME.  */
+
+bool
+fixit_remove::maybe_append_replace (line_maps *, source_range, const char *)
+{
+  return false;
+}
+
 /* class fixit_replace.  */
 
 fixit_replace::fixit_replace (source_range src_range,
@@ -2179,3 +2246,22 @@ fixit_replace::affects_line_p (const char *file, int line)
 {
   return m_src_range.intersects_line_p (file, line);
 }
+
+/* FIXME.  */
+
+bool
+fixit_replace::maybe_append_replace (line_maps *set,
+				     source_range src_range,
+				     const char *new_content)
+{
+  if (!column_before_p (set, m_src_range.m_finish, src_range.m_start))
+    return false;
+
+  /* We have neighoring replacements; merge them.  */
+  m_src_range.m_finish = src_range.m_finish;
+  size_t extra_len = strlen (new_content);
+  m_bytes = (char *)xrealloc (m_bytes, m_len + extra_len);
+  memcpy (m_bytes + m_len, new_content, extra_len);
+  m_len += extra_len;
+  return true;
+}
-- 
1.8.5.3

