Add gcc_rich_location::add_fixit_insert_formatted
authorDavid Malcolm <dmalcolm@redhat.com>
Tue, 1 May 2018 00:10:10 +0000 (00:10 +0000)
committerDavid Malcolm <dmalcolm@gcc.gnu.org>
Tue, 1 May 2018 00:10:10 +0000 (00:10 +0000)
This patch adds a support function to class gcc_rich_location
to make it easier for fix-it hints to use idiomatic C/C++
indentation, for use by the patch for PR c++/85523.

gcc/ChangeLog:
PR c++/85523
* gcc-rich-location.c (blank_line_before_p): New function.
(use_new_line): New function.
(gcc_rich_location::add_fixit_insert_formatted): New function.
* gcc-rich-location.h
(gcc_rich_location::add_fixit_insert_formatted): New function.

gcc/testsuite/ChangeLog:
PR c++/85523
* gcc.dg/plugin/diagnostic-test-show-locus-generate-patch.c
(test_add_fixit_insert_formatted_single_line): New function.
(test_add_fixit_insert_formatted_multiline): New function.
Extend expected output of generated patch to include fix-it hints
for these.
* gcc.dg/plugin/diagnostic_plugin_test_show_locus.c: Include
"gcc-rich-location.h".  Add test coverage for
gcc_rich_location::add_fixit_insert_formatted.

From-SVN: r259783

gcc/ChangeLog
gcc/gcc-rich-location.c
gcc/gcc-rich-location.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-generate-patch.c
gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c

index 84d5bd1..60ca47c 100644 (file)
@@ -1,5 +1,14 @@
 2018-04-30  David Malcolm  <dmalcolm@redhat.com>
 
+       PR c++/85523
+       * gcc-rich-location.c (blank_line_before_p): New function.
+       (use_new_line): New function.
+       (gcc_rich_location::add_fixit_insert_formatted): New function.
+       * gcc-rich-location.h
+       (gcc_rich_location::add_fixit_insert_formatted): New function.
+
+2018-04-30  David Malcolm  <dmalcolm@redhat.com>
+
        * selftest.c (assert_streq): Rename "expected" and "actual" to
        "val1" and "val2".  Extend NULL-handling to cover both inputs
        symmetrically, while still requiring both to be non-NULL for a pass.
index 3481425..0a0adf9 100644 (file)
@@ -69,3 +69,114 @@ gcc_rich_location::add_fixit_misspelled_id (location_t misspelled_token_loc,
 
   add_fixit_replace (misspelled_token_loc, IDENTIFIER_POINTER (hint_id));
 }
+
+/* Return true if there is nothing on LOC's line before LOC.  */
+
+static bool
+blank_line_before_p (location_t loc)
+{
+  expanded_location exploc = expand_location (loc);
+  char_span line = location_get_source_line (exploc.file, exploc.line);
+  if (!line)
+    return false;
+  if (line.length () < (size_t)exploc.column)
+    return false;
+  /* Columns are 1-based.  */
+  for (int column = 1; column < exploc.column; ++column)
+    if (!ISSPACE (line[column - 1]))
+      return false;
+  return true;
+}
+
+/* Subroutine of gcc_rich_location::add_fixit_insert_formatted.
+   Return true if we should add the content on its own line,
+   false otherwise.
+   If true is returned then *OUT_START_OF_LINE is written to.  */
+
+static bool
+use_new_line (location_t insertion_point, location_t indent,
+             location_t *out_start_of_line)
+{
+  if (indent == UNKNOWN_LOCATION)
+    return false;
+  const line_map *indent_map = linemap_lookup (line_table, indent);
+  if (linemap_macro_expansion_map_p (indent_map))
+    return false;
+
+  if (!blank_line_before_p (insertion_point))
+    return false;
+
+  /* Locate the start of the line containing INSERTION_POINT.  */
+  const line_map *insertion_point_map
+    = linemap_lookup (line_table, insertion_point);
+  if (linemap_macro_expansion_map_p (insertion_point_map))
+    return false;
+  const line_map_ordinary *ordmap
+    = linemap_check_ordinary (insertion_point_map);
+  expanded_location exploc_insertion_point = expand_location (insertion_point);
+  location_t start_of_line
+    = linemap_position_for_line_and_column (line_table, ordmap,
+                                           exploc_insertion_point.line, 1);
+  *out_start_of_line = start_of_line;
+  return true;
+}
+
+/* Add a fix-it hint suggesting the insertion of CONTENT before
+   INSERTION_POINT.
+
+   Attempt to handle formatting: if INSERTION_POINT is the first thing on
+   its line, and INDENT is sufficiently sane, then add CONTENT on its own
+   line, using the indentation of INDENT.
+   Otherwise, add CONTENT directly before INSERTION_POINT.
+
+   For example, adding "CONTENT;" with the closing brace as the insertion
+   point and "INDENT;" as the indentation point:
+
+   if ()
+     {
+       INDENT;
+     }
+
+  would lead to:
+
+   if ()
+     {
+       INDENT;
+       CONTENT;
+     }
+
+  but adding it to:
+
+    if () {INDENT;}
+
+  would lead to:
+
+    if () {INDENT;CONTENT;}
+*/
+
+void
+gcc_rich_location::add_fixit_insert_formatted (const char *content,
+                                              location_t insertion_point,
+                                              location_t indent)
+{
+  location_t start_of_line;
+  if (use_new_line (insertion_point, indent, &start_of_line))
+    {
+      /* Add CONTENT on its own line, using the indentation of INDENT.  */
+
+      /* Generate an insertion string, indenting by the amount INDENT
+        was indented.  */
+      int indent_column = LOCATION_COLUMN (get_start (indent));
+      pretty_printer tmp_pp;
+      pretty_printer *pp = &tmp_pp;
+      /* Columns are 1-based.  */
+      for (int column = 1; column < indent_column; ++column)
+       pp_space (pp);
+      pp_string (pp, content);
+      pp_newline (pp);
+
+      add_fixit_insert_before (start_of_line, pp_formatted_text (pp));
+    }
+  else
+    add_fixit_insert_before (insertion_point, content);
+}
index bdcf8ae..9c705c8 100644 (file)
@@ -61,6 +61,42 @@ class gcc_rich_location : public rich_location
      Implemented in diagnostic-show-locus.c.  */
 
   bool add_location_if_nearby (location_t loc);
+
+  /* Add a fix-it hint suggesting the insertion of CONTENT before
+     INSERTION_POINT.
+
+     Attempt to handle formatting: if INSERTION_POINT is the first thing on
+     its line, and INDENT is sufficiently sane, then add CONTENT on its own
+     line, using the indentation of INDENT.
+     Otherwise, add CONTENT directly before INSERTION_POINT.
+
+     For example, adding "CONTENT;" with the closing brace as the insertion
+     point and using "INDENT;" for indentation:
+
+       if ()
+         {
+           INDENT;
+         }
+
+     would lead to:
+
+       if ()
+         {
+           INDENT;
+           CONTENT;
+         }
+
+     but adding it to:
+
+       if () {INDENT;}
+
+     would lead to:
+
+       if () {INDENT;CONTENT;}
+  */
+  void add_fixit_insert_formatted (const char *content,
+                                  location_t insertion_point,
+                                  location_t indent);
 };
 
 #endif /* GCC_RICH_LOCATION_H */
index 557ac8d..7e0a41e 100644 (file)
@@ -1,5 +1,17 @@
 2018-04-30  David Malcolm  <dmalcolm@redhat.com>
 
+       PR c++/85523
+       * gcc.dg/plugin/diagnostic-test-show-locus-generate-patch.c
+       (test_add_fixit_insert_formatted_single_line): New function.
+       (test_add_fixit_insert_formatted_multiline): New function.
+       Extend expected output of generated patch to include fix-it hints
+       for these.
+       * gcc.dg/plugin/diagnostic_plugin_test_show_locus.c: Include
+       "gcc-rich-location.h".  Add test coverage for
+       gcc_rich_location::add_fixit_insert_formatted.
+
+2018-04-30  David Malcolm  <dmalcolm@redhat.com>
+
        * gcc.dg/plugin/diagnostic_plugin_test_show_locus.c
        (test_show_locus): Update for location_get_source_line returning a
        char_span.  Use char_span for handling words in the
index f1963dd..cfdc208 100644 (file)
@@ -64,6 +64,21 @@ void test_mutually_exclusive_suggestions (void)
 #endif
 }
 
+/* Unit tests for add_fixit_insert_formatted.  */
+
+void test_add_fixit_insert_formatted_single_line (void)
+{
+  {}
+}
+
+void test_add_fixit_insert_formatted_multiline (void)
+{
+  if (1)
+    {
+    }
+}
+
+
 /* Verify the output from -fdiagnostics-generate-patch.
    We expect a header, containing the filename.  This is the absolute path,
    so we can only capture it via regexps.  */
@@ -108,4 +123,21 @@ void test_mutually_exclusive_suggestions (void)
      case 'b':
        x = b;
      }
+@@ -68,7 +69,7 @@
+ void test_add_fixit_insert_formatted_single_line (void)
+ {
+-  {}
++  {INSERTED-CONTENT}
+ }
+ void test_add_fixit_insert_formatted_multiline (void)
+@@ -76,6 +77,7 @@
+   if (1)
+     {
+     }
++  INSERTED-CONTENT
+ }
    { dg-end-multiline-output "" } */
index dabc0e4..1d340aa 100644 (file)
@@ -60,6 +60,7 @@
 #include "diagnostic.h"
 #include "context.h"
 #include "print-tree.h"
+#include "gcc-rich-location.h"
 
 int plugin_is_GPL_compatible;
 
@@ -333,6 +334,29 @@ test_show_locus (function *fun)
       }
     }  
 
+  /* Tests of gcc_rich_location::add_fixit_insert_formatted.  */
+
+  if (0 == strcmp (fnname, "test_add_fixit_insert_formatted_single_line"))
+    {
+      const int line = fnstart_line + 1;
+      location_t insertion_point = get_loc (line, 3);
+      location_t indent = get_loc (line, 2);
+      gcc_rich_location richloc (insertion_point);
+      richloc.add_fixit_insert_formatted ("INSERTED-CONTENT",
+                                         insertion_point, indent);
+      inform (&richloc, "single-line insertion");
+    }
+
+  if (0 == strcmp (fnname, "test_add_fixit_insert_formatted_multiline"))
+    {
+      location_t insertion_point = fun->function_end_locus;
+      location_t indent = get_loc (fnstart_line + 1, 2);
+      gcc_rich_location richloc (insertion_point);
+      richloc.add_fixit_insert_formatted ("INSERTED-CONTENT",
+                                         insertion_point, indent);
+      inform (&richloc, "multiline insertion");
+    }
+
   /* 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.