Documentation hyperlinks for [-Wname-of-option] (PR 87488)
authorDavid Malcolm <dmalcolm@redhat.com>
Thu, 10 Oct 2019 17:03:46 +0000 (17:03 +0000)
committerDavid Malcolm <dmalcolm@gcc.gnu.org>
Thu, 10 Oct 2019 17:03:46 +0000 (17:03 +0000)
This patch uses the support for pretty-printing escaped URLs added in
the previous patch (PR 87488) so that in a sufficiently capable terminal
the [-Wname-of-option] emitted at the end of each diagnostic becomes a
hyperlink to the documentation for that option on the GCC website.

I've tested it with Fedora 30's GNOME Terminal (3.32.2 with VTE 0.56.3);
the option text is printed with a dotted underline, hovering shows the
URL, and on right-clicking it offers menu items to visit/copy the URL.

gcc/ChangeLog:
PR 87488
* Makefile.in (CFLAGS-opts.o): Pass in DOCUMENTATION_ROOT_URL via
-D.
* configure.ac (--with-documentation-root-url): New option.
* configure: Regenerate.
* diagnostic-format-json.cc (json_end_diagnostic): If there is an
option URL, add it as a new string field of the diagnostic option.
* diagnostic.c (diagnostic_initialize): Initialize get_option_url.
(print_option_information): If get_option_url is non-NULL, call
it, and if the result is non-NULL, potentially emit an escape
sequence to markup the option text with the resulting URL.
* diagnostic.h (diagnostic_context::get_option_url): New callback.
* doc/invoke.texi (-fdiagnostics-format=): Add "option_url" to
example of JSON output.
* opts-diagnostic.h (get_option_url): New decl.
* opts.c (get_option_url): New function.
* toplev.c (general_init): Initialize the get_option_url callback.

gcc/testsuite/ChangeLog:
PR 87488
* c-c++-common/diagnostic-format-json-2.c: Expect an "option_url"
field.
* c-c++-common/diagnostic-format-json-3.c: Likewise.
* gfortran.dg/diagnostic-format-json-2.F90: Likewise.
* gfortran.dg/diagnostic-format-json-3.F90: Likewise.
* jit.dg/test-error-array-bounds.c (create_code): Ensure that
error messages don't contain escaped URLs.

From-SVN: r276843

18 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/configure
gcc/configure.ac
gcc/diagnostic-format-json.cc
gcc/diagnostic.c
gcc/diagnostic.h
gcc/doc/invoke.texi
gcc/opts-diagnostic.h
gcc/opts.c
gcc/testsuite/ChangeLog
gcc/testsuite/c-c++-common/diagnostic-format-json-2.c
gcc/testsuite/c-c++-common/diagnostic-format-json-3.c
gcc/testsuite/c-c++-common/diagnostic-format-json-4.c
gcc/testsuite/gfortran.dg/diagnostic-format-json-2.F90
gcc/testsuite/gfortran.dg/diagnostic-format-json-3.F90
gcc/testsuite/jit.dg/test-error-array-bounds.c
gcc/toplev.c

index 9c34213997f0c83c782058380bd91c0d0a6be4cf..4409d4595c463b7a3334e73cac87b51272aa9845 100644 (file)
@@ -5,6 +5,26 @@
        predicate.
        (vcond<V_HW:mode><V_HW2:mode>): Use vcond_comparison_operator.
 
+2019-10-10  David Malcolm  <dmalcolm@redhat.com>
+
+       PR 87488
+       * Makefile.in (CFLAGS-opts.o): Pass in DOCUMENTATION_ROOT_URL via
+       -D.
+       * configure.ac (--with-documentation-root-url): New option.
+       * configure: Regenerate.
+       * diagnostic-format-json.cc (json_end_diagnostic): If there is an
+       option URL, add it as a new string field of the diagnostic option.
+       * diagnostic.c (diagnostic_initialize): Initialize get_option_url.
+       (print_option_information): If get_option_url is non-NULL, call
+       it, and if the result is non-NULL, potentially emit an escape
+       sequence to markup the option text with the resulting URL.
+       * diagnostic.h (diagnostic_context::get_option_url): New callback.
+       * doc/invoke.texi (-fdiagnostics-format=): Add "option_url" to
+       example of JSON output.
+       * opts-diagnostic.h (get_option_url): New decl.
+       * opts.c (get_option_url): New function.
+       * toplev.c (general_init): Initialize the get_option_url callback.
+
 2019-10-10  David Malcolm  <dmalcolm@redhat.com>
 
        PR 87488
index 59adfaa38622ff639371dab526fee0988ca5d68d..c82858fa93e7619be13a765215b97b727d7dd6d2 100644 (file)
@@ -2142,6 +2142,8 @@ lto-wrapper$(exeext): $(LTO_WRAPPER_OBJS) libcommon-target.a $(LIBDEPS)
           $(LTO_WRAPPER_OBJS) libcommon-target.a $(LIBS)
        mv -f T$@ $@
 
+CFLAGS-opts.o += -DDOCUMENTATION_ROOT_URL=\"@DOCUMENTATION_ROOT_URL@\"
+
 # Files used by all variants of C or by the stand-alone pre-processor.
 
 CFLAGS-c-family/c-opts.o += @TARGET_SYSTEM_ROOT_DEFINE@
index dc9f5fefaa80077befa8b80df1e83d1f043e8518..9de9ef85f2481130236c73f8eb1576cbe1e2cc27 100755 (executable)
@@ -815,6 +815,7 @@ accel_dir_suffix
 real_target_noncanonical
 enable_as_accelerator
 gnat_install_lib
+DOCUMENTATION_ROOT_URL
 REPORT_BUGS_TEXI
 REPORT_BUGS_TO
 PKGVERSION
@@ -960,6 +961,7 @@ enable_gcov
 with_specs
 with_pkgversion
 with_bugurl
+with_documentation_root_url
 enable_languages
 with_multilib_list
 with_zstd
@@ -1788,6 +1790,8 @@ Optional Packages:
   --with-specs=SPECS      add SPECS to driver command-line processing
   --with-pkgversion=PKG   Use PKG in the version string in place of "GCC"
   --with-bugurl=URL       Direct users to URL to report a bug
+  --with-documentation-root-url=URL
+                          Root for documentation URLs
   --with-multilib-list    select multilibs (AArch64, SH and x86-64 only)
   --with-zstd=PATH        specify prefix directory for installed zstd library.
                           Equivalent to --with-zstd-include=PATH/include plus
@@ -7802,6 +7806,23 @@ fi
 
 
 
+# Allow overriding the default URL for documentation
+
+# Check whether --with-documentation-root-url was given.
+if test "${with_documentation_root_url+set}" = set; then :
+  withval=$with_documentation_root_url; case "$withval" in
+      yes) as_fn_error $? "documentation root URL not specified" "$LINENO" 5 ;;
+      no)  as_fn_error $? "documentation root URL not specified" "$LINENO" 5 ;;
+      *)   DOCUMENTATION_ROOT_URL="$withval"
+          ;;
+     esac
+else
+  DOCUMENTATION_ROOT_URL="https://gcc.gnu.org/onlinedocs/gcc/"
+
+fi
+
+
+
 # Sanity check enable_languages in case someone does not run the toplevel
 # configure # script.
 # Check whether --enable-languages was given.
@@ -18830,7 +18851,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 18833 "configure"
+#line 18854 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -18936,7 +18957,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 18939 "configure"
+#line 18960 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
index 54a67159b989fae37a34d961bbcd3280eb3d5a4f..62f4b2651cc006e8045b45aec0aecfa9302d8bfd 100644 (file)
@@ -960,6 +960,20 @@ AC_SUBST(CONFIGURE_SPECS)
 ACX_PKGVERSION([GCC])
 ACX_BUGURL([https://gcc.gnu.org/bugs/])
 
+# Allow overriding the default URL for documentation
+AC_ARG_WITH(documentation-root-url,
+    AS_HELP_STRING([--with-documentation-root-url=URL],
+                   [Root for documentation URLs]),
+    [case "$withval" in
+      yes) AC_MSG_ERROR([documentation root URL not specified]) ;;
+      no)  AC_MSG_ERROR([documentation root URL not specified]) ;;
+      *)   DOCUMENTATION_ROOT_URL="$withval"
+          ;;
+     esac],
+     DOCUMENTATION_ROOT_URL="https://gcc.gnu.org/onlinedocs/gcc/"
+)
+AC_SUBST(DOCUMENTATION_ROOT_URL)
+
 # Sanity check enable_languages in case someone does not run the toplevel
 # configure # script.
 AC_ARG_ENABLE(languages,
index 53c3b630b1cda0e6ab5b130501beb6319b34a234..eb999521a5472ee3c1aa0422065d02bcb8a0c5ee 100644 (file)
@@ -154,6 +154,17 @@ json_end_diagnostic (diagnostic_context *context, diagnostic_info *diagnostic,
       free (option_text);
     }
 
+  if (context->get_option_url)
+    {
+      char *option_url = context->get_option_url (context,
+                                                 diagnostic->option_index);
+      if (option_url)
+       {
+         diag_obj->set ("option_url", new json::string (option_url));
+         free (option_url);
+       }
+    }
+
   /* If we've already emitted a diagnostic within this auto_diagnostic_group,
      then add diag_obj to its "children" array.  */
   if (cur_group)
index 467cc3963e60e6fa40805972014e3a57b4dfa5bf..a29bcf155e27d79feca93d4f2c3b837d55d33b45 100644 (file)
@@ -200,6 +200,7 @@ diagnostic_initialize (diagnostic_context *context, int n_opts)
   context->option_enabled = NULL;
   context->option_state = NULL;
   context->option_name = NULL;
+  context->get_option_url = NULL;
   context->last_location = UNKNOWN_LOCATION;
   context->last_module = 0;
   context->x_data = NULL;
@@ -912,11 +913,22 @@ print_option_information (diagnostic_context *context,
 
   if (option_text)
     {
+      char *option_url = NULL;
+      if (context->get_option_url)
+       option_url = context->get_option_url (context,
+                                             diagnostic->option_index);
       pretty_printer *pp = context->printer;
       pp_string (pp, " [");
       pp_string (pp, colorize_start (pp_show_color (pp),
                                     diagnostic_kind_color[diagnostic->kind]));
+      if (option_url)
+       pp_begin_url (pp, option_url);
       pp_string (pp, option_text);
+      if (option_url)
+       {
+         pp_end_url (pp);
+         free (option_url);
+       }
       pp_string (pp, colorize_stop (pp_show_color (pp)));
       pp_character (pp, ']');
       free (option_text);
index f0ea8e8bd4cc86f4eb9f96d3e1565dc16c93d0e0..91e4c50960510c8113bef80985e1ec87af162a49 100644 (file)
@@ -194,6 +194,12 @@ struct diagnostic_context
      May be passed 0 as well as the index of a particular option.  */
   char *(*option_name) (diagnostic_context *, int, diagnostic_t, diagnostic_t);
 
+  /* Client hook to return a URL describing the option that controls
+     a diagnostic.  Returns malloced memory.  May return NULL if no URL
+     is available.  May be passed 0 as well as the index of a
+     particular option.  */
+  char *(*get_option_url) (diagnostic_context *, int);
+
   /* Auxiliary data for client.  */
   void *x_data;
 
index bdbcd95d55979771f2d514c67896d955e843172e..085e8b0b2cac0b6f55d795b18ca4541f924e7c33 100644 (file)
@@ -4116,6 +4116,7 @@ might be printed in JSON form (after formatting) like this:
         ],
         "message": "this \u2018if\u2019 clause does not guard...",
         "option": "-Wmisleading-indentation",
+        "option_url": "https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#index-Wmisleading-indentation",
         "children": [
             @{
                 "kind": "note",
index 08110afe3e0a85e8a1cb144201d609343fcff4ee..3f58ae91bf64c3ffa9887a2b42ed4eb8bc201996 100644 (file)
@@ -22,4 +22,7 @@ along with GCC; see the file COPYING3.  If not see
 
 extern char *option_name (diagnostic_context *context, int option_index,
                          diagnostic_t orig_diag_kind, diagnostic_t diag_kind);
+
+extern char *get_option_url (diagnostic_context *context, int option_index);
+
 #endif
index 1070b9de955430e8b224017e15715873421f59ea..32869ca49191a8f780a3503466b160a5f172a566 100644 (file)
@@ -3218,3 +3218,24 @@ option_name (diagnostic_context *context, int option_index,
   else
     return NULL;
 }
+
+/* Return malloced memory for a URL describing the option OPTION_INDEX
+   which enabled a diagnostic (context CONTEXT).  */
+
+char *
+get_option_url (diagnostic_context *, int option_index)
+{
+  if (option_index)
+    /* DOCUMENTATION_ROOT_URL should be supplied via -D by the Makefile
+       (see --with-documentation-root-url).
+
+       Expect an anchor of the form "index-Wfoo" e.g.
+       <a name="index-Wformat"></a>, and thus an id within
+       the URL of "#index-Wformat".  */
+    return concat (DOCUMENTATION_ROOT_URL,
+                  "Warning-Options.html",
+                  "#index", cl_options[option_index].opt_text,
+                  NULL);
+  else
+    return NULL;
+}
index b6e9d88aa40c19f7aa7a6e61e0270763da4b61f2..c3f588058f3a7ed59ca76f43a8e67480527e42ca 100644 (file)
@@ -1,3 +1,14 @@
+2019-10-10  David Malcolm  <dmalcolm@redhat.com>
+
+       PR 87488
+       * c-c++-common/diagnostic-format-json-2.c: Expect an "option_url"
+       field.
+       * c-c++-common/diagnostic-format-json-3.c: Likewise.
+       * gfortran.dg/diagnostic-format-json-2.F90: Likewise.
+       * gfortran.dg/diagnostic-format-json-3.F90: Likewise.
+       * jit.dg/test-error-array-bounds.c (create_code): Ensure that
+       error messages don't contain escaped URLs.
+
 2019-10-10  David Malcolm  <dmalcolm@redhat.com>
 
        PR 87488
index 239c75ed769f93944ab2119878cb8ce2bbf940e8..557ccf8378b32501ee841c1d309b7f5e81574703 100644 (file)
@@ -10,6 +10,7 @@
 /* { dg-regexp "\"kind\": \"warning\"" } */
 /* { dg-regexp "\"message\": \"#warning message\"" } */
 /* { dg-regexp "\"option\": \"-Wcpp\"" } */
+/* { dg-regexp "\"option_url\": \"https:\[^\n\r\"\]*#index-Wcpp\"" } */
 
 /* { dg-regexp "\"caret\": \{" } */
 /* { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-2.c\"" } */
index 1c54ecacc9fd9a602bb04b47b2354dcb8d69ebcf..378205c5bf56d493017a37080414d0735a4052ec 100644 (file)
@@ -10,6 +10,7 @@
 /* { dg-regexp "\"kind\": \"error\"" } */
 /* { dg-regexp "\"message\": \"#warning message\"" } */
 /* { dg-regexp "\"option\": \"-Werror=cpp\"" } */
+/* { dg-regexp "\"option_url\": \"https:\[^\n\r\"\]*#index-Wcpp\"" } */
 
 /* { dg-regexp "\"caret\": \{" } */
 /* { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-3.c\"" } */
index 1c3b0343b6fb7c5a99a65c069c135c6d5a55f444..2738be6548fbcfdfea72e8201c3aae6dec3497a3 100644 (file)
@@ -30,13 +30,12 @@ int test (void)
 /* { dg-regexp "\"line\": 8" } */
 /* { dg-regexp "\"column\": 10" } */
 
-/* { dg-regexp "\"locations\": \[\[\{\}, \]*\]" } */
-
 /* The outer diagnostic.  */
 
 /* { dg-regexp "\"kind\": \"warning\"" } */
 /* { dg-regexp "\"message\": \"this 'if' clause does not guard...\"" } */
 /* { dg-regexp "\"option\": \"-Wmisleading-indentation\"" } */
+/* { dg-regexp "\"option_url\": \"https:\[^\n\r\"\]*#index-Wmisleading-indentation\"" } */
 
 /* { dg-regexp "\"caret\": \{" } */
 /* { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-4.c\"" } */
@@ -48,6 +47,13 @@ int test (void)
 /* { dg-regexp "\"line\": 6" } */
 /* { dg-regexp "\"column\": 4" } */
 
+/* More from the nested diagnostic (we can't guarantee what order the
+   "file" keys are consumed).  */
+
+/* { dg-regexp "\"locations\": \[\[\{\}, \]*\]" } */
+
+/* More from the outer diagnostic.  */
+
 /* { dg-regexp "\"locations\": \[\[\{\}, \]*\]" } */
 
 /* { dg-regexp "\"children\": \[\[\{\}, \]*\]" } */
index a6d27d9e16a64dd26def5d75e5d7140bd66bb02d..bebcf68d43118b423b7e30b86e9951053be394bd 100644 (file)
@@ -10,6 +10,7 @@
 ! { dg-regexp "\"kind\": \"warning\"" }
 ! { dg-regexp "\"message\": \"#warning message\"" }
 ! { dg-regexp "\"option\": \"-Wcpp\"" }
+! { dg-regexp "\"option_url\": \"\[^\n\r\"\]*#index-Wcpp\"" }
 
 ! { dg-regexp "\"caret\": \{" }
 ! { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-2.F90\"" }
index 702a937d9c63e79da8e34aff2d3e4b65afc708a6..7ab78eb570b99f196246d4432e82d0ea4ea6ee68 100644 (file)
@@ -10,6 +10,7 @@
 ! { dg-regexp "\"kind\": \"error\"" }
 ! { dg-regexp "\"message\": \"#warning message\"" }
 ! { dg-regexp "\"option\": \"-Werror=cpp\"" }
+! { dg-regexp "\"option_url\": \"\[^\n\r\"\]*#index-Wcpp\"" }
 
 ! { dg-regexp "\"caret\": \{" }
 ! { dg-regexp "\"file\": \"\[^\n\r\"\]*diagnostic-format-json-3.F90\"" }
index 889c51737a419424f969ee439a6d5e89f7deb5bc..cd9361fba1da9c1c5d27f3abd7eeae925bf926c8 100644 (file)
@@ -20,9 +20,10 @@ create_code (gcc_jit_context *ctxt, void *user_data)
   gcc_jit_context_add_command_line_option (ctxt, "-Warray-bounds");
   gcc_jit_context_add_command_line_option (ctxt, "-ftree-vrp");
 
-  /* Ensure that the error message doesn't contain colorization codes,
-     even if run at a TTY.  */
+  /* Ensure that the error message doesn't contain colorization codes
+     or escaped URLs, even if run at a TTY.  */
   gcc_jit_context_add_command_line_option (ctxt, "-fdiagnostics-color=never");
+  gcc_jit_context_add_command_line_option (ctxt, "-fdiagnostics-urls=never");
 
   gcc_jit_type *char_type =
     gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CHAR);
index b85d52ca9b797487ef91b04fab21150b0215645d..1c7002f5c37cddf39c16a01b233bf058d2bd3041 100644 (file)
@@ -1110,6 +1110,7 @@ general_init (const char *argv0, bool init_signals)
   global_dc->option_enabled = option_enabled;
   global_dc->option_state = &global_options;
   global_dc->option_name = option_name;
+  global_dc->get_option_url = get_option_url;
 
   if (init_signals)
     {