[committed] Add gcc_rich_location::add_fixit_insert_formatted

David Malcolm dmalcolm@redhat.com
Tue May 1 00:12:00 GMT 2018


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.

Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.

Committed to trunk as r259783.

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.
---
 gcc/gcc-rich-location.c                            | 111 +++++++++++++++++++++
 gcc/gcc-rich-location.h                            |  36 +++++++
 .../diagnostic-test-show-locus-generate-patch.c    |  32 ++++++
 .../plugin/diagnostic_plugin_test_show_locus.c     |  24 +++++
 4 files changed, 203 insertions(+)

diff --git a/gcc/gcc-rich-location.c b/gcc/gcc-rich-location.c
index 3481425..0a0adf9 100644
--- a/gcc/gcc-rich-location.c
+++ b/gcc/gcc-rich-location.c
@@ -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);
+}
diff --git a/gcc/gcc-rich-location.h b/gcc/gcc-rich-location.h
index bdcf8ae..9c705c8 100644
--- a/gcc/gcc-rich-location.h
+++ b/gcc/gcc-rich-location.h
@@ -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 */
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-generate-patch.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-generate-patch.c
index f1963dd..cfdc208 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-generate-patch.c
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-generate-patch.c
@@ -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 "" } */
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c
index dabc0e4..1d340aa 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.c
@@ -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.
-- 
1.8.5.3



More information about the Gcc-patches mailing list