PR 62314: add ability to add fixit-hints to a diagnostic
authorDavid Malcolm <dmalcolm@redhat.com>
Fri, 20 Nov 2015 20:08:47 +0000 (20:08 +0000)
committerDavid Malcolm <dmalcolm@gcc.gnu.org>
Fri, 20 Nov 2015 20:08:47 +0000 (20:08 +0000)
This is the combination of two patches:
  [PATCH 01/02] PR/62314: add ability to add fixit-hints
  [PATCH 02/02] C FE: add fix-it hint for . vs ->

gcc/ChangeLog:
PR 62314
* diagnostic-show-locus.c (colorizer::set_fixit_hint): New.
(class layout): Update comment
(layout::print_any_fixits): New method.
(layout::move_to_column): New method.
(diagnostic_show_locus): Add call to layout.print_any_fixits.

gcc/c/ChangeLog:
PR 62314
* c-typeck.c (should_suggest_deref_p): New function.
(build_component_ref): Special-case POINTER_TYPE when
generating a "not a structure of union"  error message, and
suggest a "->" rather than a ".", providing a fix-it hint.

gcc/testsuite/ChangeLog:
PR 62314
* gcc.dg/fixits.c: New file.
* gcc.dg/plugin/diagnostic-test-show-locus-ascii-bw.c
(test_fixit_insert): New.
(test_fixit_remove): New.
(test_fixit_replace): New.
* gcc.dg/plugin/diagnostic-test-show-locus-ascii-color.c
(test_fixit_insert): New.
(test_fixit_remove): New.
(test_fixit_replace): New.
* gcc.dg/plugin/diagnostic_plugin_test_show_locus.c
(test_show_locus): Add tests of rendering fixit hints.

libcpp/ChangeLog:
PR 62314
* include/line-map.h (source_range::intersects_line_p): New
method.
(rich_location::~rich_location): New.
(rich_location::add_fixit_insert): New method.
(rich_location::add_fixit_remove): New method.
(rich_location::add_fixit_replace): New method.
(rich_location::get_num_fixit_hints): New accessor.
(rich_location::get_fixit_hint): New accessor.
(rich_location::MAX_FIXIT_HINTS): New constant.
(rich_location::m_num_fixit_hints): New field.
(rich_location::m_fixit_hints): New field.
(class fixit_hint): New class.
(class fixit_insert): New class.
(class fixit_remove): New class.
(class fixit_replace): New class.
* line-map.c (source_range::intersects_line_p): New method.
(rich_location::rich_location): Add initialization of
m_num_fixit_hints to both ctors.
(rich_location::~rich_location): New.
(rich_location::add_fixit_insert): New method.
(rich_location::add_fixit_remove): New method.
(rich_location::add_fixit_replace): New method.
(fixit_insert::fixit_insert): New.
(fixit_insert::~fixit_insert): New.
(fixit_insert::affects_line_p): New.
(fixit_remove::fixit_remove): New.
(fixit_remove::affects_line_p): New.
(fixit_replace::fixit_replace): New.
(fixit_replace::~fixit_replace): New.
(fixit_replace::affects_line_p): New.

From-SVN: r230674

12 files changed:
gcc/ChangeLog
gcc/c/ChangeLog
gcc/c/c-typeck.c
gcc/diagnostic-show-locus.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/fixits.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-bw.c
gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-color.c
gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c
libcpp/ChangeLog
libcpp/include/line-map.h
libcpp/line-map.c

index 4d3e5b3680f57830ee210ccdda7d493a0aadca64..54ae9221fce92ff42a6175f0e2192d5bdd0a8c0d 100644 (file)
@@ -1,3 +1,12 @@
+2015-11-20  David Malcolm  <dmalcolm@redhat.com>
+
+       PR 62314
+       * diagnostic-show-locus.c (colorizer::set_fixit_hint): New.
+       (class layout): Update comment
+       (layout::print_any_fixits): New method.
+       (layout::move_to_column): New method.
+       (diagnostic_show_locus): Add call to layout.print_any_fixits.
+
 2015-11-20  Jakub Jelinek  <jakub@redhat.com>
 
        PR middle-end/68221
index 9399053a7f9f5375c4aa6ff7bd4ad42e1e09858b..96c5823d66cbc35246974cf3948a2d8c5ec12382 100644 (file)
@@ -1,3 +1,11 @@
+2015-11-20  David Malcolm  <dmalcolm@redhat.com>
+
+       PR 62314
+       * c-typeck.c (should_suggest_deref_p): New function.
+       (build_component_ref): Special-case POINTER_TYPE when
+       generating a "not a structure of union"  error message, and
+       suggest a "->" rather than a ".", providing a fix-it hint.
+
 2015-11-19  David Malcolm  <dmalcolm@redhat.com>
 
        * c-typeck.c (lookup_field_fuzzy): Move determination of closest
index 9284bfcea66e464a679609792ffb59f348b76439..741c75cb169bc11f6265cc3391d6d26e2c9149f1 100644 (file)
@@ -2277,6 +2277,33 @@ lookup_field_fuzzy (tree type, tree component)
   return find_closest_identifier (component, &candidates);
 }
 
+/* Support function for build_component_ref's error-handling.
+
+   Given DATUM_TYPE, and "DATUM.COMPONENT", where DATUM is *not* a
+   struct or union, should we suggest "DATUM->COMPONENT" as a hint?  */
+
+static bool
+should_suggest_deref_p (tree datum_type)
+{
+  /* We don't do it for Objective-C, since Objective-C 2.0 dot-syntax
+     allows "." for ptrs; we could be handling a failed attempt
+     to access a property.  */
+  if (c_dialect_objc ())
+    return false;
+
+  /* Only suggest it for pointers...  */
+  if (TREE_CODE (datum_type) != POINTER_TYPE)
+    return false;
+
+  /* ...to structs/unions.  */
+  tree underlying_type = TREE_TYPE (datum_type);
+  enum tree_code code = TREE_CODE (underlying_type);
+  if (code == RECORD_TYPE || code == UNION_TYPE)
+    return true;
+  else
+    return false;
+}
+
 /* Make an expression to refer to the COMPONENT field of structure or
    union value DATUM.  COMPONENT is an IDENTIFIER_NODE.  LOC is the
    location of the COMPONENT_REF.  */
@@ -2369,6 +2396,18 @@ build_component_ref (location_t loc, tree datum, tree component)
 
       return ref;
     }
+  else if (should_suggest_deref_p (type))
+    {
+      /* Special-case the error message for "ptr.field" for the case
+        where the user has confused "." vs "->".  */
+      rich_location richloc (line_table, loc);
+      /* "loc" should be the "." token.  */
+      richloc.add_fixit_replace (source_range::from_location (loc), "->");
+      error_at_rich_loc (&richloc,
+                        "%qE is a pointer; did you mean to use %<->%>?",
+                        datum);
+      return error_mark_node;
+    }
   else if (code != ERROR_MARK)
     error_at (loc,
              "request for member %qE in something not a structure or union",
index 22203cdbaa380d88aef3f8f2b38ea265d6f08d13..9e51b95655a0b29e6ebf76f5acd9b425263f754a 100644 (file)
@@ -78,6 +78,7 @@ class colorizer
 
   void set_range (int range_idx) { set_state (range_idx); }
   void set_normal_text () { set_state (STATE_NORMAL_TEXT); }
+  void set_fixit_hint () { set_state (0); }
 
  private:
   void set_state (int state);
@@ -139,8 +140,8 @@ struct line_bounds
 /* A class to control the overall layout when printing a diagnostic.
 
    The layout is determined within the constructor.
-   It is then printed by repeatedly calling the "print_source_line"
-   and "print_annotation_line" methods.
+   It is then printed by repeatedly calling the "print_source_line",
+   "print_annotation_line" and "print_any_fixits" methods.
 
    We assume we have disjoint ranges.  */
 
@@ -155,6 +156,7 @@ class layout
 
   bool print_source_line (int row, line_bounds *lbounds_out);
   void print_annotation_line (int row, const line_bounds lbounds);
+  void print_any_fixits (int row, const rich_location *richloc);
 
  private:
   bool
@@ -168,6 +170,9 @@ class layout
   get_x_bound_for_row (int row, int caret_column,
                       int last_non_ws);
 
+  void
+  move_to_column (int *column, int dest_column);
+
  private:
   diagnostic_context *m_context;
   pretty_printer *m_pp;
@@ -593,6 +598,73 @@ layout::print_annotation_line (int row, const line_bounds lbounds)
   pp_newline (m_pp);
 }
 
+/* If there are any fixit hints on source line ROW within RICHLOC, print them.
+   They are printed in order, attempting to combine them onto lines, but
+   starting new lines if necessary.  */
+
+void
+layout::print_any_fixits (int row, const rich_location *richloc)
+{
+  int column = 0;
+  for (unsigned int i = 0; i < richloc->get_num_fixit_hints (); i++)
+    {
+      fixit_hint *hint = richloc->get_fixit_hint (i);
+      if (hint->affects_line_p (m_exploc.file, row))
+       {
+         /* For now we assume each fixit hint can only touch one line.  */
+         switch (hint->get_kind ())
+           {
+           case fixit_hint::INSERT:
+             {
+               fixit_insert *insert = static_cast <fixit_insert *> (hint);
+               /* This assumes the insertion just affects one line.  */
+               int start_column
+                 = LOCATION_COLUMN (insert->get_location ());
+               move_to_column (&column, start_column);
+               m_colorizer.set_fixit_hint ();
+               pp_string (m_pp, insert->get_string ());
+               m_colorizer.set_normal_text ();
+               column += insert->get_length ();
+             }
+             break;
+
+           case fixit_hint::REMOVE:
+             {
+               fixit_remove *remove = static_cast <fixit_remove *> (hint);
+               /* This assumes the removal just affects one line.  */
+               source_range src_range = remove->get_range ();
+               int start_column = LOCATION_COLUMN (src_range.m_start);
+               int finish_column = LOCATION_COLUMN (src_range.m_finish);
+               move_to_column (&column, start_column);
+               for (int column = start_column; column <= finish_column; column++)
+                 {
+                   m_colorizer.set_fixit_hint ();
+                   pp_character (m_pp, '-');
+                   m_colorizer.set_normal_text ();
+                 }
+             }
+             break;
+
+           case fixit_hint::REPLACE:
+             {
+               fixit_replace *replace = static_cast <fixit_replace *> (hint);
+               int start_column
+                 = LOCATION_COLUMN (replace->get_range ().m_start);
+               move_to_column (&column, start_column);
+               m_colorizer.set_fixit_hint ();
+               pp_string (m_pp, replace->get_string ());
+               m_colorizer.set_normal_text ();
+               column += replace->get_length ();
+             }
+             break;
+
+           default:
+             gcc_unreachable ();
+           }
+       }
+    }
+}
+
 /* Return true if (ROW/COLUMN) is within a range of the layout.
    If it returns true, OUT_STATE is written to, with the
    range index, and whether we should draw the caret at
@@ -675,6 +747,27 @@ layout::get_x_bound_for_row (int row, int caret_column,
   return result;
 }
 
+/* Given *COLUMN as an x-coordinate, print spaces to position
+   successive output at DEST_COLUMN, printing a newline if necessary,
+   and updating *COLUMN.  */
+
+void
+layout::move_to_column (int *column, int dest_column)
+{
+  /* Start a new line if we need to.  */
+  if (*column > dest_column)
+    {
+      pp_newline (m_pp);
+      *column = 0;
+    }
+
+  while (*column < dest_column)
+    {
+      pp_space (m_pp);
+      (*column)++;
+    }
+}
+
 } /* End of anonymous namespace.  */
 
 /* Print the physical source code corresponding to the location of
@@ -704,11 +797,14 @@ diagnostic_show_locus (diagnostic_context * context,
         row++)
       {
        /* Print the source line, followed by an annotation line
-          consisting of any caret/underlines.  If the source line can't
-          be read, print nothing.  */
+          consisting of any caret/underlines, then any fixits.
+          If the source line can't be read, print nothing.  */
        line_bounds lbounds;
        if (layout.print_source_line (row, &lbounds))
-         layout.print_annotation_line (row, lbounds);
+         {
+           layout.print_annotation_line (row, lbounds);
+           layout.print_any_fixits (row, diagnostic->richloc);
+         }
       }
 
     /* The closing scope here leads to the dtor for layout and thus
index de70aae1a04155bdb240ed1f6a83ab51a77d1f3d..84659a559b9e62bfda954e211e492c2b4563d810 100644 (file)
@@ -1,3 +1,18 @@
+2015-11-20  David Malcolm  <dmalcolm@redhat.com>
+
+       PR 62314
+       * gcc.dg/fixits.c: New file.
+       * gcc.dg/plugin/diagnostic-test-show-locus-ascii-bw.c
+       (test_fixit_insert): New.
+       (test_fixit_remove): New.
+       (test_fixit_replace): New.
+       * gcc.dg/plugin/diagnostic-test-show-locus-ascii-color.c
+       (test_fixit_insert): New.
+       (test_fixit_remove): New.
+       (test_fixit_replace): New.
+       * gcc.dg/plugin/diagnostic_plugin_test_show_locus.c
+       (test_show_locus): Add tests of rendering fixit hints.
+
 2015-11-20  Jakub Jelinek  <jakub@redhat.com>
 
        PR middle-end/68339
diff --git a/gcc/testsuite/gcc.dg/fixits.c b/gcc/testsuite/gcc.dg/fixits.c
new file mode 100644 (file)
index 0000000..06c9995
--- /dev/null
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-options "-fdiagnostics-show-caret" } */
+
+struct foo { int x; };
+union u { int x; };
+
+/* Verify that we issue a hint for "." used with a ptr to a struct.  */
+
+int test_1 (struct foo *ptr)
+{
+  return ptr.x; /* { dg-error "'ptr' is a pointer; did you mean to use '->'?" } */
+/* { dg-begin-multiline-output "" }
+   return ptr.x;
+             ^
+             ->
+   { dg-end-multiline-output "" } */
+}
+
+/* Likewise for a ptr to a union.  */
+
+int test_2 (union u *ptr)
+{
+  return ptr.x; /* { dg-error "'ptr' is a pointer; did you mean to use '->'?" } */
+/* { dg-begin-multiline-output "" }
+   return ptr.x;
+             ^
+             ->
+   { dg-end-multiline-output "" } */
+}
+
+/* Verify that we don't issue a hint for a ptr to something that isn't a
+   struct or union.  */
+
+int test_3 (void **ptr)
+{
+  return ptr.x; /* { dg-error "request for member 'x' in something not a structure or union" } */
+/* { dg-begin-multiline-output "" }
+   return ptr.x;
+             ^
+   { dg-end-multiline-output "" } */
+}
index a4b16da318c5490eede8e58ddd2d0d87ebfdc25a..44b47e0f38b33de39c96c6106ad0a7e6ab1a88ce 100644 (file)
@@ -147,3 +147,46 @@ void test_caret_on_leading_whitespace (void)
    { dg-end-multiline-output "" } */
 #endif
 }
+
+/* Unit test for rendering of insertion fixit hints
+   (example taken from PR 62316).  */
+
+void test_fixit_insert (void)
+{
+#if 0
+   int a[2][2] = { 0, 1 , 2, 3 }; /* { dg-warning "insertion hints" } */
+/* { dg-begin-multiline-output "" }
+    int a[2][2] = { 0, 1 , 2, 3 };
+                    ^~~~
+                    {   }
+   { dg-end-multiline-output "" } */
+#endif
+}
+
+/* Unit test for rendering of "remove" fixit hints.  */
+
+void test_fixit_remove (void)
+{
+#if 0
+  int a;; /* { dg-warning "example of a removal hint" } */
+/* { dg-begin-multiline-output "" }
+   int a;;
+         ^
+         -
+   { dg-end-multiline-output "" } */
+#endif
+}
+
+/* Unit test for rendering of "replace" fixit hints.  */
+
+void test_fixit_replace (void)
+{
+#if 0
+  gtk_widget_showall (dlg); /* { dg-warning "example of a replacement hint" } */
+/* { dg-begin-multiline-output "" }
+   gtk_widget_showall (dlg);
+   ^~~~~~~~~~~~~~~~~~
+   gtk_widget_show_all
+   { dg-end-multiline-output "" } */
+#endif
+}
index 47639b22fc976db66032f8a2a6d5228178b14167..199e0b20d6198ec76c5f655457c7609b95fe405e 100644 (file)
@@ -156,3 +156,46 @@ void test_caret_on_leading_whitespace (void)
    { dg-end-multiline-output "" } */
 #endif
 }
+
+/* Unit test for rendering of insertion fixit hints
+   (example taken from PR 62316).  */
+
+void test_fixit_insert (void)
+{
+#if 0
+   int a[2][2] = { 0, 1 , 2, 3 }; /* { dg-warning "insertion hints" } */
+/* { dg-begin-multiline-output "" }
+    int a[2][2] = { \e[01;35m\e[K0, 1\e[m\e[K , 2, 3 };
+                    \e[01;35m\e[K^~~~
+                    {\e[m\e[K   \e[01;35m\e[K}\e[m\e[K
+   { dg-end-multiline-output "" } */
+#endif
+}
+
+/* Unit test for rendering of "remove" fixit hints.  */
+
+void test_fixit_remove (void)
+{
+#if 0
+  int a;; /* { dg-warning "example of a removal hint" } */
+/* { dg-begin-multiline-output "" }
+   int a;\e[01;35m\e[K;\e[m\e[K
+         \e[01;35m\e[K^
+         -\e[m\e[K
+   { dg-end-multiline-output "" } */
+#endif
+}
+
+/* Unit test for rendering of "replace" fixit hints.  */
+
+void test_fixit_replace (void)
+{
+#if 0
+  gtk_widget_showall (dlg); /* { dg-warning "example of a replacement hint" } */
+/* { dg-begin-multiline-output "" }
+   \e[01;35m\e[Kgtk_widget_showall\e[m\e[K (dlg);
+   \e[01;35m\e[K^~~~~~~~~~~~~~~~~~
+   gtk_widget_show_all\e[m\e[K
+   { dg-end-multiline-output "" } */
+#endif
+}
index 158c6124a996fb15f6c310d83babda92cb5229e4..7ff2cff79eeab63ee28ce6726908603bc293d891 100644 (file)
@@ -258,6 +258,41 @@ test_show_locus (function *fun)
       global_dc->caret_chars[1] = '^';
     }
 
+  /* Tests of rendering fixit hints.  */
+  if (0 == strcmp (fnname, "test_fixit_insert"))
+    {
+      const int line = fnstart_line + 2;
+      source_range src_range;
+      src_range.m_start = get_loc (line, 19);
+      src_range.m_finish = get_loc (line, 22);
+      rich_location richloc (src_range);
+      richloc.add_fixit_insert (src_range.m_start, "{");
+      richloc.add_fixit_insert (get_loc (line, 23), "}");
+      warning_at_rich_loc (&richloc, 0, "example of insertion hints");
+    }
+
+  if (0 == strcmp (fnname, "test_fixit_remove"))
+    {
+      const int line = fnstart_line + 2;
+      source_range src_range;
+      src_range.m_start = get_loc (line, 8);
+      src_range.m_finish = get_loc (line, 8);
+      rich_location richloc (src_range);
+      richloc.add_fixit_remove (src_range);
+      warning_at_rich_loc (&richloc, 0, "example of a removal hint");
+    }
+
+  if (0 == strcmp (fnname, "test_fixit_replace"))
+    {
+      const int line = fnstart_line + 2;
+      source_range src_range;
+      src_range.m_start = get_loc (line, 2);
+      src_range.m_finish = get_loc (line, 19);
+      rich_location richloc (src_range);
+      richloc.add_fixit_replace (src_range, "gtk_widget_show_all");
+      warning_at_rich_loc (&richloc, 0, "example of a replacement hint");
+    }
+
   /* Example of two carets where both carets appear to have an off-by-one
      error appearing one column early.
      Seen with gfortran.dg/associate_5.f03.
index ce294ae88abd21dae6fe45217bf5c2180bc3038d..78a0d7cb373ed502b0919b476743592eb21c5e3e 100644 (file)
@@ -1,3 +1,37 @@
+2015-11-20  David Malcolm  <dmalcolm@redhat.com>
+
+       PR 62314
+       * include/line-map.h (source_range::intersects_line_p): New
+       method.
+       (rich_location::~rich_location): New.
+       (rich_location::add_fixit_insert): New method.
+       (rich_location::add_fixit_remove): New method.
+       (rich_location::add_fixit_replace): New method.
+       (rich_location::get_num_fixit_hints): New accessor.
+       (rich_location::get_fixit_hint): New accessor.
+       (rich_location::MAX_FIXIT_HINTS): New constant.
+       (rich_location::m_num_fixit_hints): New field.
+       (rich_location::m_fixit_hints): New field.
+       (class fixit_hint): New class.
+       (class fixit_insert): New class.
+       (class fixit_remove): New class.
+       (class fixit_replace): New class.
+       * line-map.c (source_range::intersects_line_p): New method.
+       (rich_location::rich_location): Add initialization of
+       m_num_fixit_hints to both ctors.
+       (rich_location::~rich_location): New.
+       (rich_location::add_fixit_insert): New method.
+       (rich_location::add_fixit_remove): New method.
+       (rich_location::add_fixit_replace): New method.
+       (fixit_insert::fixit_insert): New.
+       (fixit_insert::~fixit_insert): New.
+       (fixit_insert::affects_line_p): New.
+       (fixit_remove::fixit_remove): New.
+       (fixit_remove::affects_line_p): New.
+       (fixit_replace::fixit_replace): New.
+       (fixit_replace::~fixit_replace): New.
+       (fixit_replace::affects_line_p): New.
+
 2015-11-19  Jakub Jelinek  <jakub@redhat.com>
 
        PR preprocessor/60736
index e7608f1e468f54d784cac4cea6c02cf76454329e..4f440fa5e51887af5a8e854fdda1c79aff0b16ea 100644 (file)
@@ -299,6 +299,9 @@ struct GTY(()) source_range
     result.m_finish = loc;
     return result;
   }
+
+  /* Is there any part of this range on the given line?  */
+  bool intersects_line_p (const char *file, int line) const;
 };
 
 /* Memory allocation function typedef.  Works like xrealloc.  */
@@ -1267,6 +1270,11 @@ struct location_range
   expanded_location m_caret;
 };
 
+class fixit_hint;
+  class fixit_insert;
+  class fixit_remove;
+  class fixit_replace;
+
 /* A "rich" source code location, for use when printing diagnostics.
    A rich_location has one or more ranges, each optionally with
    a caret.   Typically the zeroth range has a caret; other ranges
@@ -1349,6 +1357,9 @@ class rich_location
   /* Constructing from a source_range.  */
   rich_location (source_range src_range);
 
+  /* Destructor.  */
+  ~rich_location ();
+
   /* Accessors.  */
   source_location get_loc () const { return m_loc; }
 
@@ -1381,8 +1392,24 @@ class rich_location
   void
   override_column (int column);
 
+  /* Fix-it hints.  */
+  void
+  add_fixit_insert (source_location where,
+                   const char *new_content);
+
+  void
+  add_fixit_remove (source_range src_range);
+
+  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_hint *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:
   source_location m_loc;
@@ -1392,8 +1419,77 @@ protected:
 
   bool m_have_expanded_location;
   expanded_location m_expanded_location;
+
+  unsigned int m_num_fixit_hints;
+  fixit_hint *m_fixit_hints[MAX_FIXIT_HINTS];
+};
+
+class fixit_hint
+{
+public:
+  enum kind {INSERT, REMOVE, REPLACE};
+
+  virtual ~fixit_hint () {}
+
+  virtual enum kind get_kind () const = 0;
+  virtual bool affects_line_p (const char *file, int line) = 0;
+};
+
+class fixit_insert : public fixit_hint
+{
+ public:
+  fixit_insert (source_location where,
+               const char *new_content);
+  ~fixit_insert ();
+  enum kind get_kind () const { return INSERT; }
+  bool affects_line_p (const char *file, int line);
+
+  source_location get_location () const { return m_where; }
+  const char *get_string () const { return m_bytes; }
+  size_t get_length () const { return m_len; }
+
+ private:
+  source_location m_where;
+  char *m_bytes;
+  size_t m_len;
+};
+
+class fixit_remove : public fixit_hint
+{
+ public:
+  fixit_remove (source_range src_range);
+  ~fixit_remove () {}
+
+  enum kind get_kind () const { return REMOVE; }
+  bool affects_line_p (const char *file, int line);
+
+  source_range get_range () const { return m_src_range; }
+
+ private:
+  source_range m_src_range;
 };
 
+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; }
+  bool affects_line_p (const char *file, int line);
+
+  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; }
+
+ private:
+  source_range m_src_range;
+  char *m_bytes;
+  size_t m_len;
+};
+
+
 /* This is enum is used by the function linemap_resolve_location
    below.  The meaning of the values is explained in the comment of
    that function.  */
index c5aa4223b1be18753c2284226dbbe3721c901f53..42843038e3bf2c89fa25f78647f269a8f7c94999 100644 (file)
@@ -1947,6 +1947,28 @@ line_table_dump (FILE *stream, struct line_maps *set, unsigned int num_ordinary,
     }
 }
 
+/* struct source_range.  */
+
+/* Is there any part of this range on the given line?  */
+
+bool
+source_range::intersects_line_p (const char *file, int line) const
+{
+  expanded_location exploc_start
+    = linemap_client_expand_location_to_spelling_point (m_start);
+  if (file != exploc_start.file)
+    return false;
+  if (line < exploc_start.line)
+      return false;
+  expanded_location exploc_finish
+    = linemap_client_expand_location_to_spelling_point (m_finish);
+  if (file != exploc_finish.file)
+    return false;
+  if (line > exploc_finish.line)
+      return false;
+  return true;
+}
+
 /* class rich_location.  */
 
 /* Construct a rich_location with location LOC as its initial range.  */
@@ -1954,7 +1976,8 @@ line_table_dump (FILE *stream, struct line_maps *set, unsigned int num_ordinary,
 rich_location::rich_location (line_maps *set, 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, extracting any range from LOC.  */
   source_range src_range = get_range_from_loc (set, loc);
@@ -1968,12 +1991,21 @@ rich_location::rich_location (line_maps *set, 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);
 }
 
+/* The destructor for class rich_location.  */
+
+rich_location::~rich_location ()
+{
+  for (unsigned int i = 0; i < m_num_fixit_hints; i++)
+    delete m_fixit_hints[i];
+}
+
 /* Get an expanded_location for this rich_location's primary
    location.  */
 
@@ -2077,3 +2109,103 @@ rich_location::set_range (unsigned int idx, source_range src_range,
       m_have_expanded_location = false;
     }
 }
+
+/* Add a fixit-hint, suggesting insertion of NEW_CONTENT
+   at WHERE.  */
+
+void
+rich_location::add_fixit_insert (source_location where,
+                                const char *new_content)
+{
+  linemap_assert (m_num_fixit_hints < MAX_FIXIT_HINTS);
+  m_fixit_hints[m_num_fixit_hints++]
+    = new fixit_insert (where, new_content);
+}
+
+/* Add a fixit-hint, suggesting removal of the content at
+   SRC_RANGE.  */
+
+void
+rich_location::add_fixit_remove (source_range src_range)
+{
+  linemap_assert (m_num_fixit_hints < MAX_FIXIT_HINTS);
+  m_fixit_hints[m_num_fixit_hints++] = new fixit_remove (src_range);
+}
+
+/* Add a fixit-hint, suggesting replacement of the content at
+   SRC_RANGE with NEW_CONTENT.  */
+
+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);
+}
+
+/* class fixit_insert.  */
+
+fixit_insert::fixit_insert (source_location where,
+                           const char *new_content)
+: m_where (where),
+  m_bytes (xstrdup (new_content)),
+  m_len (strlen (new_content))
+{
+}
+
+fixit_insert::~fixit_insert ()
+{
+  free (m_bytes);
+}
+
+/* Implementation of fixit_hint::affects_line_p for fixit_insert.  */
+
+bool
+fixit_insert::affects_line_p (const char *file, int line)
+{
+  expanded_location exploc
+    = linemap_client_expand_location_to_spelling_point (m_where);
+  if (file == exploc.file)
+    if (line == exploc.line)
+      return true;
+  return false;
+}
+
+/* class fixit_remove.  */
+
+fixit_remove::fixit_remove (source_range src_range)
+: m_src_range (src_range)
+{
+}
+
+/* Implementation of fixit_hint::affects_line_p for fixit_remove.  */
+
+bool
+fixit_remove::affects_line_p (const char *file, int line)
+{
+  return m_src_range.intersects_line_p (file, line);
+}
+
+/* class fixit_replace.  */
+
+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);
+}
+
+/* Implementation of fixit_hint::affects_line_p for fixit_replace.  */
+
+bool
+fixit_replace::affects_line_p (const char *file, int line)
+{
+  return m_src_range.intersects_line_p (file, line);
+}