From 6326a7689a202c0ace1bd27bb7bd2cc758007399 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Mon, 7 Sep 2015 10:56:04 -0400
Subject: [PATCH 50/71] FIXME: Start adding fixme hints (just 'replace' for
 now)

---
 gcc/c/c-parser.c                  | 12 +++++--
 gcc/c/c-typeck.c                  |  3 ++
 gcc/diagnostic-show-locus.c       | 33 +++++++++++++++++++
 gcc/testsuite/gcc.dg/spellcheck.c |  8 ++++-
 libcpp/include/line-map.h         | 68 +++++++++++++++++++++++++++++++++++++++
 libcpp/line-map.c                 | 32 ++++++++++++++++--
 6 files changed, 150 insertions(+), 6 deletions(-)

diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 15809b9..9b07e9c 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -1546,9 +1546,15 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
     {
       tree hint = lookup_name_fuzzy (c_parser_peek_token (parser)->value);
       if (hint)
-	error_at (here, "unknown type name %qE; did you mean %qE?",
-		  c_parser_peek_token (parser)->value,
-		  hint);
+	{
+	  rich_location richloc (here);
+	  richloc.add_fixit_replace (here,
+				     IDENTIFIER_POINTER (hint));
+	  error_at_rich_loc (&richloc,
+			     "unknown type name %qE; did you mean %qE?",
+			     c_parser_peek_token (parser)->value,
+			     hint);
+	}
       else
 	error_at (here, "unknown type name %qE",
 		  c_parser_peek_token (parser)->value);
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 6a05219..376b30c 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -2367,6 +2367,9 @@ build_component_ref (location_t loc, tree datum, tree component,
 	  field = spellcheck_lookup_field (type, component);
 	  if (field)
 	    {
+	      richloc.add_fixit_replace
+		(*ident_range,
+		 IDENTIFIER_POINTER (DECL_NAME (field)));
 	      error_at_rich_loc
 		(&richloc,
 		 "%qT has no member named %qE; did you mean %qE?",
diff --git a/gcc/diagnostic-show-locus.c b/gcc/diagnostic-show-locus.c
index 78c4364..6648356 100644
--- a/gcc/diagnostic-show-locus.c
+++ b/gcc/diagnostic-show-locus.c
@@ -743,6 +743,39 @@ layout::print_line (int row)
     }
   print_any_margin (row, x_bound, PRINT_LINE_KIND_ANNOTATION);
   pp_newline (m_pp);
+
+  /* Step 3a: are there are any fixit hints on this source line?  */
+
+  bool line_has_fixits;
+  expanded_location fixit_exploc[rich_location::MAX_FIXIT_HINTS];
+  for (unsigned int i = 0; i < m_richloc->get_num_fixit_hints (); i++)
+    {
+      fixit_replace *hint = m_richloc->get_fixit_hint (i);
+      fixit_exploc[i]
+	= linemap_client_expand_location_to_spelling_point (hint->m_src_range.m_start);
+      if (fixit_exploc[i].line == row)
+	line_has_fixits = true;
+    }
+
+  if (!line_has_fixits)
+    return;
+
+  /* Step 3b: if there are any fixit hints on this source line, print a line
+     describing them.  */
+  pp_space (m_pp);
+  for (int column = 1; column < x_bound; column++)
+    {
+      bool got_start = false;
+      for (unsigned int i = 0; i < m_richloc->get_num_fixit_hints (); i++)
+	if (column == fixit_exploc[i].column)
+	  {
+	    got_start = true;
+	    pp_string (m_pp, m_richloc->get_fixit_hint (i)->m_bytes);
+	  }
+        
+      if (!got_start)
+	pp_character (m_pp, ' ');
+    }
 }
 
 /* Given a line of source code, get the per_range_info for the first range
diff --git a/gcc/testsuite/gcc.dg/spellcheck.c b/gcc/testsuite/gcc.dg/spellcheck.c
index e34ade8..93626d8 100644
--- a/gcc/testsuite/gcc.dg/spellcheck.c
+++ b/gcc/testsuite/gcc.dg/spellcheck.c
@@ -15,7 +15,9 @@ int test (struct foo *ptr)
 /* { dg-begin-multiline-output "" }
    return ptr->m_bar;
           ~~~  ^~~~~
+               bar    
    { dg-end-multiline-output "" } */
+/* FIXME: trailing whitespace */
 }
 
 int test2 (void)
@@ -26,11 +28,15 @@ int test2 (void)
 /* { dg-begin-multiline-output "" }
    return instance.m_bar;
           ~~~~~~~~ ^~~~~
+                   bar    
    { dg-end-multiline-output "" } */
+/* FIXME: trailing whitespace */
 }
 
-int64 foo; /* { dg-error "unknown type name 'int64'; did you mean 'int'?" } */
+#include <inttypes.h>
+int64 foo; /* { dg-error "unknown type name 'int64'; did you mean 'int64_t'?" } */
 /* { dg-begin-multiline-output "" }
  int64 foo;
  ^~~~~
+ int64_t
    { dg-end-multiline-output "" } */
diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h
index 060af1e..48ca909 100644
--- a/libcpp/include/line-map.h
+++ b/libcpp/include/line-map.h
@@ -1093,6 +1093,9 @@ enum buffer_ownership
   BUFFER_OWNERSHIP_BORROWED /* Make a copy.  */
 };
 
+class fixit_hint;
+class fixit_replace;
+
 /* A "rich" source code location, for use when printing diagnostics.
    A rich_location is a position, along with one or more ranges.
    They are intended to be allocated on the stack when generating
@@ -1189,8 +1192,16 @@ class rich_location
   void
   override_column (int column);
 
+  void
+  add_fixit_replace (source_range src_range,
+		     const char *new_content);
+
+  unsigned int get_num_fixit_hints () const { return m_num_fixit_hints; }
+  fixit_replace *get_fixit_hint (int idx) const { return m_fixit_hints[idx]; }
+
 public:
   static const int MAX_RANGES = 3;
+  static const int MAX_FIXIT_HINTS = 2;
 
 protected:
   friend class range_iter;
@@ -1202,8 +1213,65 @@ protected:
 
   bool m_have_expanded_location;
   expanded_location m_expanded_location;
+
+  unsigned int m_num_fixit_hints;
+#if 0
+  fixit_hint *m_fixit_hints[MAX_FIXIT_HINTS];
+#else
+  fixit_replace *m_fixit_hints[MAX_FIXIT_HINTS];
+#endif
+};
+
+class fixit_hint
+{
+public:
+  enum kind {INSERT, REMOVE, REPLACE};
+
+  virtual ~fixit_hint () {}
+
+  virtual enum kind get_kind () const = 0;
 };
 
+#if 0
+class fixit_insert : public fixit_hint
+{
+ public:
+  ~fixit_insert ();
+  enum kind get_kind () const { return INSERT; }
+
+ private:
+  source_location m_loc;
+  char *m_bytes;
+  size_t m_len;
+};
+
+class fixit_remove : public fixit_hint
+{
+ public:
+  ~fixit_remove ();
+  enum kind get_kind () const { return REMOVE; }
+
+ private:
+  source_location m_loc;
+  size_t m_len;
+};
+#endif
+
+class fixit_replace : public fixit_hint
+{
+ public:
+  fixit_replace (source_range src_range,
+                 const char *new_content);
+  ~fixit_replace ();
+  enum kind get_kind () const { return REPLACE; }
+
+  //private:
+  source_range m_src_range;
+  char *m_bytes;
+  size_t m_len;
+};
+
+
 inline
 rich_location::range_iter::range_iter (rich_location *richloc) :
   m_richloc (richloc),
diff --git a/libcpp/line-map.c b/libcpp/line-map.c
index 2846103..8f61e4a 100644
--- a/libcpp/line-map.c
+++ b/libcpp/line-map.c
@@ -1754,7 +1754,8 @@ line_table_dump (FILE *stream, struct line_maps *set, unsigned int num_ordinary,
 rich_location::rich_location (source_location loc) :
   m_loc (loc),
   m_num_ranges (0),
-  m_have_expanded_location (false)
+  m_have_expanded_location (false),
+  m_num_fixit_hints (0)
 {
   /* Set up the 0th range: */
   add_range (loc, loc, true);
@@ -1766,7 +1767,8 @@ rich_location::rich_location (source_location loc) :
 rich_location::rich_location (source_range src_range)
 : m_loc (src_range.m_start),
   m_num_ranges (0),
-  m_have_expanded_location (false)
+  m_have_expanded_location (false),
+  m_num_fixit_hints (0)
 {
   /* Set up the 0th range: */
   add_range (src_range, true);
@@ -1778,6 +1780,8 @@ rich_location::~rich_location ()
 {
   for (unsigned int i = 0; i < m_num_ranges; i++)
     free (m_ranges[i].m_caption);
+  for (unsigned int i = 0; i < m_num_fixit_hints; i++)
+    delete m_fixit_hints[i];
 }
 
 /* FIXME.  */
@@ -1951,3 +1955,27 @@ rich_location::set_range (unsigned int idx, source_range src_range,
       m_have_expanded_location = false;
     }
 }
+
+void
+rich_location::add_fixit_replace (source_range src_range,
+				  const char *new_content)
+{
+  linemap_assert (m_num_fixit_hints < MAX_FIXIT_HINTS);
+  m_fixit_hints[m_num_fixit_hints++] = new fixit_replace (src_range, new_content);
+  /* FIXME */
+  /* should this be a method of the base class?  how to render?  */
+  /* figure out which lines are affected; print them under the annotation lines */
+}
+
+fixit_replace::fixit_replace (source_range src_range,
+			      const char *new_content)
+: m_src_range (src_range),
+  m_bytes (xstrdup (new_content)),
+  m_len (strlen (new_content))
+{
+}
+
+fixit_replace::~fixit_replace ()
+{
+  free (m_bytes);
+}
-- 
1.8.5.3

