Implement -fdiagnostics-parseable-fixits
authorDavid Malcolm <dmalcolm@redhat.com>
Wed, 22 Jun 2016 14:42:30 +0000 (14:42 +0000)
committerDavid Malcolm <dmalcolm@gcc.gnu.org>
Wed, 22 Jun 2016 14:42:30 +0000 (14:42 +0000)
gcc/ChangeLog:
* common.opt (fdiagnostics-parseable-fixits): New option.
* diagnostic.c: Include "selftest.h".
(print_escaped_string): New function.
(print_parseable_fixits): New function.
(diagnostic_report_diagnostic): Call print_parseable_fixits.
(selftest::assert_print_escaped_string): New function.
(ASSERT_PRINT_ESCAPED_STRING_STREQ): New macro.
(selftest::test_print_escaped_string): New function.
(selftest::test_print_parseable_fixits_none): New function.
(selftest::test_print_parseable_fixits_insert): New function.
(selftest::test_print_parseable_fixits_remove): New function.
(selftest::test_print_parseable_fixits_replace): New function.
(selftest::diagnostic_c_tests): New function.
* diagnostic.h (struct diagnostic_context): Add field
"parseable_fixits_p".
* doc/invoke.texi (Diagnostic Message Formatting Options): Add
-fdiagnostics-parseable-fixits.
(-fdiagnostics-parseable-fixits): New option.
* opts.c (common_handle_option): Handle
-fdiagnostics-parseable-fixits.
* selftest-run-tests.c (selftest::run_tests): Call
selftest::diagnostic_c_tests.
* selftest.h (selftest::diagnostic_c_tests): New prototype.

gcc/testsuite/ChangeLog:
* gcc.dg/plugin/diagnostic-test-show-locus-parseable-fixits.c: New
file.
* gcc.dg/plugin/plugin.exp (plugin_test_list): Add
diagnostic-test-show-locus-parseable-fixits.c to sources for
diagnostic_plugin_test_show_locus.c.
* lib/gcc-defs.exp (freeform_regexps): New global.
(dg-regexp): New function.
(handle-dg-regexps): New function.
* lib/gcc-dg.exp (cleanup-after-saved-dg-test): Reset
freeform_regexps to the empty list.
* lib/prune.exp (prune_gcc_output): Call handle-dg-regexps.

libcpp/ChangeLog:
* include/line-map.h (fixit_hint::get_start_loc): New pure virtual
function.
(fixit_hint::maybe_get_end_loc): Likewise.
(fixit_insert::get_start_loc): New function, implementing
fixit_hint::get_start_loc.
(fixit_insert::maybe_get_end_loc): New function, implementing
fixit_hint::maybe_get_end_loc.
(fixit_remove::get_start_loc): New function, implementing
fixit_hint::get_start_loc.
(fixit_remove::maybe_get_end_loc): New function, implementing
fixit_hint::maybe_get_end_loc.
(fixit_replace::get_start_loc): New function, implementing
fixit_hint::get_start_loc.
(fixit_replace::maybe_get_end_loc): New function, implementing
fixit_hint::maybe_get_end_loc.

From-SVN: r237712

16 files changed:
gcc/ChangeLog
gcc/common.opt
gcc/diagnostic.c
gcc/diagnostic.h
gcc/doc/invoke.texi
gcc/opts.c
gcc/selftest-run-tests.c
gcc/selftest.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-parseable-fixits.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/plugin/plugin.exp
gcc/testsuite/lib/gcc-defs.exp
gcc/testsuite/lib/gcc-dg.exp
gcc/testsuite/lib/prune.exp
libcpp/ChangeLog
libcpp/include/line-map.h

index 7db3d032079920176ef9a174d6a068d8dcac5795..1a985a3d69ac38ef07a2a1f9c824cb320bc253ea 100644 (file)
@@ -1,3 +1,29 @@
+2016-06-22  David Malcolm  <dmalcolm@redhat.com>
+
+       * common.opt (fdiagnostics-parseable-fixits): New option.
+       * diagnostic.c: Include "selftest.h".
+       (print_escaped_string): New function.
+       (print_parseable_fixits): New function.
+       (diagnostic_report_diagnostic): Call print_parseable_fixits.
+       (selftest::assert_print_escaped_string): New function.
+       (ASSERT_PRINT_ESCAPED_STRING_STREQ): New macro.
+       (selftest::test_print_escaped_string): New function.
+       (selftest::test_print_parseable_fixits_none): New function.
+       (selftest::test_print_parseable_fixits_insert): New function.
+       (selftest::test_print_parseable_fixits_remove): New function.
+       (selftest::test_print_parseable_fixits_replace): New function.
+       (selftest::diagnostic_c_tests): New function.
+       * diagnostic.h (struct diagnostic_context): Add field
+       "parseable_fixits_p".
+       * doc/invoke.texi (Diagnostic Message Formatting Options): Add
+       -fdiagnostics-parseable-fixits.
+       (-fdiagnostics-parseable-fixits): New option.
+       * opts.c (common_handle_option): Handle
+       -fdiagnostics-parseable-fixits.
+       * selftest-run-tests.c (selftest::run_tests): Call
+       selftest::diagnostic_c_tests.
+       * selftest.h (selftest::diagnostic_c_tests): New prototype.
+
 2016-06-22  Ilya Enkovich  <ilya.enkovich@intel.com>
 
        PR middle-end/71488
index f0d71966cdf3e17945dd57892ba41dbb06d06a47..5d90385eaead0c13f1a018205a5bd5a77965c79d 100644 (file)
@@ -1185,6 +1185,10 @@ Enum(diagnostic_color_rule) String(always) Value(DIAGNOSTICS_COLOR_YES)
 EnumValue
 Enum(diagnostic_color_rule) String(auto) Value(DIAGNOSTICS_COLOR_AUTO)
 
+fdiagnostics-parseable-fixits
+Common Var(flag_diagnostics_parseable_fixits)
+Print fixit hints in machine-readable form.
+
 fdiagnostics-show-option
 Common Var(flag_diagnostics_show_option) Init(1)
 Amend appropriate diagnostic messages with the command line option that controls them.
index 8467aaa377dbb2f958d0ad860294dadfe8382eec..d39afff6622891738bfeea00d91d71bc6ca29c95 100644 (file)
@@ -31,6 +31,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "backtrace.h"
 #include "diagnostic.h"
 #include "diagnostic-color.h"
+#include "selftest.h"
 
 #ifdef HAVE_TERMIOS_H
 # include <termios.h>
@@ -667,6 +668,112 @@ diagnostic_pop_diagnostics (diagnostic_context *context, location_t where)
   context->n_classification_history ++;
 }
 
+/* Helper function for print_parseable_fixits.  Print TEXT to PP, obeying the
+   escaping rules for -fdiagnostics-parseable-fixits.  */
+
+static void
+print_escaped_string (pretty_printer *pp, const char *text)
+{
+  gcc_assert (pp);
+  gcc_assert (text);
+
+  pp_character (pp, '"');
+  for (const char *ch = text; *ch; ch++)
+    {
+      switch (*ch)
+       {
+       case '\\':
+         /* Escape backslash as two backslashes.  */
+         pp_string (pp, "\\\\");
+         break;
+       case '\t':
+         /* Escape tab as "\t".  */
+         pp_string (pp, "\\t");
+         break;
+       case '\n':
+         /* Escape newline as "\n".  */
+         pp_string (pp, "\\n");
+         break;
+       case '"':
+         /* Escape doublequotes as \".  */
+         pp_string (pp, "\\\"");
+         break;
+       default:
+         if (ISPRINT (*ch))
+           pp_character (pp, *ch);
+         else
+           /* Use octal for non-printable chars.  */
+           {
+             unsigned char c = (*ch & 0xff);
+             pp_printf (pp, "\\%o%o%o", (c / 64), (c / 8) & 007, c & 007);
+           }
+         break;
+       }
+    }
+  pp_character (pp, '"');
+}
+
+/* Implementation of -fdiagnostics-parseable-fixits.  Print a
+   machine-parseable version of all fixits in RICHLOC to PP.  */
+
+static void
+print_parseable_fixits (pretty_printer *pp, rich_location *richloc)
+{
+  gcc_assert (pp);
+  gcc_assert (richloc);
+
+  for (unsigned i = 0; i < richloc->get_num_fixit_hints (); i++)
+    {
+      const fixit_hint *hint = richloc->get_fixit_hint (i);
+      source_location start_loc = hint->get_start_loc ();
+      expanded_location start_exploc = expand_location (start_loc);
+      pp_string (pp, "fix-it:");
+      print_escaped_string (pp, start_exploc.file);
+      source_location end_loc;
+
+      /* For compatibility with clang, print as a half-open range.  */
+      if (hint->maybe_get_end_loc (&end_loc))
+       {
+         expanded_location end_exploc = expand_location (end_loc);
+         pp_printf (pp, ":{%i:%i-%i:%i}:",
+                    start_exploc.line, start_exploc.column,
+                    end_exploc.line, end_exploc.column + 1);
+       }
+      else
+       {
+         pp_printf (pp, ":{%i:%i-%i:%i}:",
+                    start_exploc.line, start_exploc.column,
+                    start_exploc.line, start_exploc.column);
+       }
+      switch (hint->get_kind ())
+       {
+         case fixit_hint::INSERT:
+           {
+             const fixit_insert *insert
+               = static_cast <const fixit_insert *> (hint);
+             print_escaped_string (pp, insert->get_string ());
+           }
+           break;
+
+         case fixit_hint::REMOVE:
+           print_escaped_string (pp, "");
+           break;
+
+         case fixit_hint::REPLACE:
+           {
+             const fixit_replace *replace
+               = static_cast <const fixit_replace *> (hint);
+             print_escaped_string (pp, replace->get_string ());
+           }
+           break;
+
+         default:
+           gcc_unreachable ();
+       }
+      pp_newline (pp);
+    }
+}
+
 /* Report a diagnostic message (an error or a warning) as specified by
    DC.  This function is *the* subroutine in terms of which front-ends
    should implement their specific diagnostic handling modules.  The
@@ -828,6 +935,11 @@ diagnostic_report_diagnostic (diagnostic_context *context,
   (*diagnostic_starter (context)) (context, diagnostic);
   pp_output_formatted_text (context->printer);
   (*diagnostic_finalizer (context)) (context, diagnostic);
+  if (context->parseable_fixits_p)
+    {
+      print_parseable_fixits (context->printer, diagnostic->richloc);
+      pp_flush (context->printer);
+    }
   diagnostic_action_after_output (context, diagnostic->kind);
   diagnostic->message.format_spec = saved_format_spec;
   diagnostic->x_data = NULL;
@@ -1290,3 +1402,149 @@ real_abort (void)
 {
   abort ();
 }
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Helper function for test_print_escaped_string.  */
+
+static void
+assert_print_escaped_string (const location &loc, const char *expected_output,
+                            const char *input)
+{
+  pretty_printer pp;
+  print_escaped_string (&pp, input);
+  ASSERT_STREQ_AT (loc, expected_output, pp_formatted_text (&pp));
+}
+
+#define ASSERT_PRINT_ESCAPED_STRING_STREQ(EXPECTED_OUTPUT, INPUT) \
+    assert_print_escaped_string (SELFTEST_LOCATION, EXPECTED_OUTPUT, INPUT)
+
+/* Tests of print_escaped_string.  */
+
+static void
+test_print_escaped_string ()
+{
+  /* Empty string.  */
+  ASSERT_PRINT_ESCAPED_STRING_STREQ ("\"\"", "");
+
+  /* Non-empty string.  */
+  ASSERT_PRINT_ESCAPED_STRING_STREQ ("\"hello world\"", "hello world");
+
+  /* Various things that need to be escaped:  */
+  /* Backslash.  */
+  ASSERT_PRINT_ESCAPED_STRING_STREQ ("\"before\\\\after\"",
+                                    "before\\after");
+  /* Tab.  */
+  ASSERT_PRINT_ESCAPED_STRING_STREQ ("\"before\\tafter\"",
+                                    "before\tafter");
+  /* Newline.  */
+  ASSERT_PRINT_ESCAPED_STRING_STREQ ("\"before\\nafter\"",
+                                    "before\nafter");
+  /* Double quote.  */
+  ASSERT_PRINT_ESCAPED_STRING_STREQ ("\"before\\\"after\"",
+                                    "before\"after");
+
+  /* Non-printable characters: BEL: '\a': 0x07 */
+  ASSERT_PRINT_ESCAPED_STRING_STREQ ("\"before\\007after\"",
+                                    "before\aafter");
+  /* Non-printable characters: vertical tab: '\v': 0x0b */
+  ASSERT_PRINT_ESCAPED_STRING_STREQ ("\"before\\013after\"",
+                                    "before\vafter");
+}
+
+/* Tests of print_parseable_fixits.  */
+
+/* Verify that print_parseable_fixits emits the empty string if there
+   are no fixits.  */
+
+static void
+test_print_parseable_fixits_none ()
+{
+  pretty_printer pp;
+  rich_location richloc (line_table, UNKNOWN_LOCATION);
+
+  print_parseable_fixits (&pp, &richloc);
+  ASSERT_STREQ ("", pp_formatted_text (&pp));
+}
+
+/* Verify that print_parseable_fixits does the right thing if there
+   is an insertion fixit hint.  */
+
+static void
+test_print_parseable_fixits_insert ()
+{
+  pretty_printer pp;
+  rich_location richloc (line_table, UNKNOWN_LOCATION);
+
+  linemap_add (line_table, LC_ENTER, false, "test.c", 0);
+  linemap_line_start (line_table, 5, 100);
+  linemap_add (line_table, LC_LEAVE, false, NULL, 0);
+  location_t where = linemap_position_for_column (line_table, 10);
+  richloc.add_fixit_insert (where, "added content");
+
+  print_parseable_fixits (&pp, &richloc);
+  ASSERT_STREQ ("fix-it:\"test.c\":{5:10-5:10}:\"added content\"\n",
+               pp_formatted_text (&pp));
+}
+
+/* Verify that print_parseable_fixits does the right thing if there
+   is an removal fixit hint.  */
+
+static void
+test_print_parseable_fixits_remove ()
+{
+  pretty_printer pp;
+  rich_location richloc (line_table, UNKNOWN_LOCATION);
+
+  linemap_add (line_table, LC_ENTER, false, "test.c", 0);
+  linemap_line_start (line_table, 5, 100);
+  linemap_add (line_table, LC_LEAVE, false, NULL, 0);
+  source_range where;
+  where.m_start = linemap_position_for_column (line_table, 10);
+  where.m_finish = linemap_position_for_column (line_table, 20);
+  richloc.add_fixit_remove (where);
+
+  print_parseable_fixits (&pp, &richloc);
+  ASSERT_STREQ ("fix-it:\"test.c\":{5:10-5:21}:\"\"\n",
+               pp_formatted_text (&pp));
+}
+
+/* Verify that print_parseable_fixits does the right thing if there
+   is an replacement fixit hint.  */
+
+static void
+test_print_parseable_fixits_replace ()
+{
+  pretty_printer pp;
+  rich_location richloc (line_table, UNKNOWN_LOCATION);
+
+  linemap_add (line_table, LC_ENTER, false, "test.c", 0);
+  linemap_line_start (line_table, 5, 100);
+  linemap_add (line_table, LC_LEAVE, false, NULL, 0);
+  source_range where;
+  where.m_start = linemap_position_for_column (line_table, 10);
+  where.m_finish = linemap_position_for_column (line_table, 20);
+  richloc.add_fixit_replace (where, "replacement");
+
+  print_parseable_fixits (&pp, &richloc);
+  ASSERT_STREQ ("fix-it:\"test.c\":{5:10-5:21}:\"replacement\"\n",
+               pp_formatted_text (&pp));
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+diagnostic_c_tests ()
+{
+  test_print_escaped_string ();
+  test_print_parseable_fixits_none ();
+  test_print_parseable_fixits_insert ();
+  test_print_parseable_fixits_remove ();
+  test_print_parseable_fixits_replace ();
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
index 58d77df61c536b64c0d6bff47a7e8d2ceeb581a3..afce2850882891564ca5ed11fe468a7ea4c727a6 100644 (file)
@@ -205,6 +205,10 @@ struct diagnostic_context
   /* Usable by plugins; if true, print a debugging ruler above the
      source output.  */
   bool show_ruler_p;
+
+  /* If true, print fixits in machine-parseable form after the
+     rest of the diagnostic.  */
+  bool parseable_fixits_p;
 };
 
 static inline void
index fdb65f025a1aa626da771a8b58651c7541385fe2..2c87c53d3d1d1aff3674a674684e24b5abb34901 100644 (file)
@@ -246,7 +246,8 @@ Objective-C and Objective-C++ Dialects}.
 @gccoptlist{-fmessage-length=@var{n}  @gol
 -fdiagnostics-show-location=@r{[}once@r{|}every-line@r{]}  @gol
 -fdiagnostics-color=@r{[}auto@r{|}never@r{|}always@r{]}  @gol
--fno-diagnostics-show-option -fno-diagnostics-show-caret}
+-fno-diagnostics-show-option -fno-diagnostics-show-caret @gol
+-fdiagnostics-parseable-fixits}
 
 @item Warning Options
 @xref{Warning Options,,Options to Request or Suppress Warnings}.
@@ -3389,6 +3390,37 @@ the @option{-fmessage-length=n} option is given.  When the output is done
 to the terminal, the width is limited to the width given by the
 @env{COLUMNS} environment variable or, if not set, to the terminal width.
 
+@item -fdiagnostics-parseable-fixits
+@opindex fdiagnostics-parseable-fixits
+Emit fix-it hints in a machine-parseable format, suitable for consumption
+by IDEs.  For each fix-it, a line will be printed after the relevant
+diagnostic, starting with the string ``fix-it:''.  For example:
+
+@smallexample
+fix-it:"test.c":@{45:3-45:21@}:"gtk_widget_show_all"
+@end smallexample
+
+The location is expressed as a half-open range, expressed as a count of
+bytes, starting at byte 1 for the initial column.  In the above example,
+bytes 3 through 20 of line 45 of ``test.c'' are to be replaced with the
+given string:
+
+@smallexample
+00000000011111111112222222222
+12345678901234567890123456789
+  gtk_widget_showall (dlg);
+  ^^^^^^^^^^^^^^^^^^
+  gtk_widget_show_all
+@end smallexample
+
+The filename and replacement string escape backslash as ``\\", tab as ``\t'',
+newline as ``\n'', double quotes as ``\"'', non-printable characters as octal
+(e.g. vertical tab as ``\013'').
+
+An empty replacement string indicates that the given range is to be removed.
+An empty range (e.g. ``45:3-45:3'') indicates that the string is to
+be inserted at the given position.
+
 @end table
 
 @node Warning Options
index e80331f4bf52c119994fb32646e924d65440049f..74062106895d2b994c83cecaf419e0cbbaa70517 100644 (file)
@@ -1871,6 +1871,10 @@ common_handle_option (struct gcc_options *opts,
       diagnostic_color_init (dc, value);
       break;
 
+    case OPT_fdiagnostics_parseable_fixits:
+      dc->parseable_fixits_p = value;
+      break;
+
     case OPT_fdiagnostics_show_option:
       dc->show_option_requested = value;
       break;
index d4a9c0b26b891a3aba90f81b6a18ebb616238991..bddf0b2d9a91fe0add7c6941a49bcc84f09bf093 100644 (file)
@@ -59,6 +59,7 @@ selftest::run_tests ()
   /* Higher-level tests, or for components that other selftests don't
      rely on.  */
   diagnostic_show_locus_c_tests ();
+  diagnostic_c_tests ();
   fold_const_c_tests ();
   spellcheck_c_tests ();
   spellcheck_tree_c_tests ();
index 2bc7316c990eaa2e27e11f9d544a1655d9f02bd3..c6becdd01dfb381868e547db1420cc7b00600175 100644 (file)
@@ -72,6 +72,7 @@ extern void assert_streq (const location &loc,
 /* Declarations for specific families of tests (by source file), in
    alphabetical order.  */
 extern void bitmap_c_tests ();
+extern void diagnostic_c_tests ();
 extern void diagnostic_show_locus_c_tests ();
 extern void et_forest_c_tests ();
 extern void fold_const_c_tests ();
index 93aad44974df99b0e308ab8bf80dc4529a97ba45..8cac69489d65c295d548aef29b2b25cf3482dbfa 100644 (file)
@@ -1,3 +1,17 @@
+2016-06-22  David Malcolm  <dmalcolm@redhat.com>
+
+       * gcc.dg/plugin/diagnostic-test-show-locus-parseable-fixits.c: New
+       file.
+       * gcc.dg/plugin/plugin.exp (plugin_test_list): Add
+       diagnostic-test-show-locus-parseable-fixits.c to sources for
+       diagnostic_plugin_test_show_locus.c.
+       * lib/gcc-defs.exp (freeform_regexps): New global.
+       (dg-regexp): New function.
+       (handle-dg-regexps): New function.
+       * lib/gcc-dg.exp (cleanup-after-saved-dg-test): Reset
+       freeform_regexps to the empty list.
+       * lib/prune.exp (prune_gcc_output): Call handle-dg-regexps.
+
 2016-06-22  Ilya Enkovich  <ilya.enkovich@intel.com>
 
        PR middle-end/71488
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-parseable-fixits.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus-parseable-fixits.c
new file mode 100644 (file)
index 0000000..1490c98
--- /dev/null
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdiagnostics-parseable-fixits" } */
+
+/* This is a collection of unittests for diagnostic_show_locus;
+   see the overview in diagnostic_plugin_test_show_locus.c.
+
+   In particular, note the discussion of why we need a very long line here:
+01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
+   and that we can't use macros in this file.  */
+
+/* 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-regexp "fix-it:.*\\{17:20-17:20\\}:.*" } */
+/* { dg-regexp "fix-it:.*\\{17:24-17:24\\}:.*" } */
+#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-regexp "fix-it:.*\\{28:9-28:10\\}:.*" } */
+#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-regexp "fix-it:.*\\{38:3-38:21\\}:.*" } */
+#endif
+}
index be2ac8dcfcb7a266cf1defbe5ff732f0de4eaf50..f039c8de35f6fd38ba83b4cc4942c6bde40236cc 100644 (file)
@@ -65,7 +65,8 @@ set plugin_test_list [list \
     { wide-int_plugin.c wide-int-test-1.c } \
     { diagnostic_plugin_test_show_locus.c \
          diagnostic-test-show-locus-bw.c \
-         diagnostic-test-show-locus-color.c } \
+         diagnostic-test-show-locus-color.c \
+         diagnostic-test-show-locus-parseable-fixits.c } \
     { diagnostic_plugin_test_tree_expression_range.c \
          diagnostic-test-expressions-1.c } \
     { diagnostic_plugin_show_trees.c \
index 0210af8e838c3f5659bc873ccc56920819cbb9fa..1186e5ba1a35f82ec3a338651a95988d89dc170b 100644 (file)
@@ -352,3 +352,54 @@ proc gcc-set-multilib-library-path { compiler } {
 
     return $libpath
 }
+
+# A list of all uses of dg-regexp, each entry of the form:
+#   line-number regexp
+# This is cleared at the end of each test by gcc-dg.exp's wrapper for dg-test.
+set freeform_regexps []
+
+# Directive for looking for a regexp, without any line numbers or other
+# prefixes.
+
+proc dg-regexp { args } {
+    verbose "dg-regexp: args: $args" 2
+
+    global freeform_regexps
+    lappend freeform_regexps $args
+}
+
+# Hook to be called by prune.exp's prune_gcc_output to
+# look for the expected dg-regexp expressions, pruning them,
+# reporting PASS for those that are found, and FAIL for
+# those that weren't found.
+#
+# It returns a pruned version of its output.
+
+proc handle-dg-regexps { text } {
+    global freeform_regexps
+    global testname_with_flags
+
+    foreach entry $freeform_regexps {
+       verbose "  entry: $entry" 3
+
+       set linenum [lindex $entry 0]
+       set rexp [lindex $entry 1]
+
+       # Escape newlines in $rexp so that we can print them in
+       # pass/fail results.
+       set escaped_regex [string map {"\n" "\\n"} $rexp]
+       verbose "escaped_regex: ${escaped_regex}" 4
+
+       set title "$testname_with_flags dg-regexp $linenum"
+
+       # Use "regsub" to attempt to prune the pattern from $text
+       if {[regsub -line $rexp $text "" text]} {
+           # Success; the multiline pattern was pruned.
+           pass "$title was found: \"$escaped_regex\""
+       } else {
+           fail "$title not found: \"$escaped_regex\""
+       }
+    }
+
+    return $text
+}
index 70391407c018192b35cfc4fa9bf039951bf7430a..b7f0ff7838a99b183249535a383dcc795f741d31 100644 (file)
@@ -899,6 +899,7 @@ if { [info procs saved-dg-test] == [list] } {
        global saved_compiler_env_var
        global keep_saved_temps_suffixes
        global multiline_expected_outputs
+       global freeform_regexps
 
        set additional_files ""
        set additional_sources ""
@@ -924,6 +925,7 @@ if { [info procs saved-dg-test] == [list] } {
            unset testname_with_flags
        }
        set multiline_expected_outputs []
+       set freeform_regexps []
     }
 
     proc dg-test { args } {
index ab6f3697ff8a300ebfcc47f59c94d34c65f86dd2..d3ff4930276a1a4bd65b19c0bdd1ac01a6dfe80f 100644 (file)
@@ -73,6 +73,9 @@ proc prune_gcc_output { text } {
     # Call into multiline.exp to handle any multiline output directives.
     set text [handle-multiline-outputs $text]
 
+    # Handle any freeform regexps.
+    set text [handle-dg-regexps $text]
+
     #send_user "After:$text\n"
 
     return $text
index c32b15725f893ae06dbd5d797d68324df4ec8150..65bfe2612e2f836ac5466855a549b4afe063bd57 100644 (file)
@@ -1,3 +1,21 @@
+2016-06-22  David Malcolm  <dmalcolm@redhat.com>
+
+       * include/line-map.h (fixit_hint::get_start_loc): New pure virtual
+       function.
+       (fixit_hint::maybe_get_end_loc): Likewise.
+       (fixit_insert::get_start_loc): New function, implementing
+       fixit_hint::get_start_loc.
+       (fixit_insert::maybe_get_end_loc): New function, implementing
+       fixit_hint::maybe_get_end_loc.
+       (fixit_remove::get_start_loc): New function, implementing
+       fixit_hint::get_start_loc.
+       (fixit_remove::maybe_get_end_loc): New function, implementing
+       fixit_hint::maybe_get_end_loc.
+       (fixit_replace::get_start_loc): New function, implementing
+       fixit_hint::get_start_loc.
+       (fixit_replace::maybe_get_end_loc): New function, implementing
+       fixit_hint::maybe_get_end_loc.
+
 2016-06-21  John David Anglin  <danglin@gcc.gnu.org>
 
        * line-map.c (location_adhoc_data_update): Use int64_t instead of
index 292abce3ec913d57f7fff1ec92b1baf196001272..416419c59d9905971470f85cfc93e77502b26623 100644 (file)
@@ -1418,6 +1418,8 @@ public:
 
   virtual enum kind get_kind () const = 0;
   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;
 };
 
 class fixit_insert : public fixit_hint
@@ -1428,6 +1430,8 @@ class fixit_insert : public fixit_hint
   ~fixit_insert ();
   enum kind get_kind () const { return INSERT; }
   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; }
 
   source_location get_location () const { return m_where; }
   const char *get_string () const { return m_bytes; }
@@ -1447,6 +1451,12 @@ class fixit_remove : public fixit_hint
 
   enum kind get_kind () const { return REMOVE; }
   bool affects_line_p (const char *file, int line);
+  source_location get_start_loc () const { return m_src_range.m_start; }
+  bool maybe_get_end_loc (source_location *out) const
+  {
+    *out = m_src_range.m_finish;
+    return true;
+  }
 
   source_range get_range () const { return m_src_range; }
 
@@ -1463,6 +1473,12 @@ class fixit_replace : public fixit_hint
 
   enum kind get_kind () const { return REPLACE; }
   bool affects_line_p (const char *file, int line);
+  source_location get_start_loc () const { return m_src_range.m_start; }
+  bool maybe_get_end_loc (source_location *out) const
+  {
+    *out = m_src_range.m_finish;
+    return true;
+  }
 
   source_range get_range () const { return m_src_range; }
   const char *get_string () const { return m_bytes; }