diagnostics: add automatic URL-ification within messages

In r10-3781-gd26082357676a3 GCC's pretty-print framework gained
the ability to emit embedding URLs via escape sequences
for marking up text output..

In r10-3783-gb4c7ca2ef3915a GCC started using this for the
[-Wname-of-option] emitted at the end of each diagnostic so that it
becomes a hyperlink to the documentation for that option on the GCC
website.

This makes it much more convenient for the user to locate pertinent
documentation when a diagnostic is emitted.

The above involved special-casing in one specific place, but there is
plenty of quoted text throughout GCC's diagnostic messages that could
usefully have a documentation URL: references to options, pragmas, etc

This patch adds a new optional "urlifier" parameter to pp_format.
The idea is that a urlifier object has responsibility for mapping from
quoted strings in diagnostic messages to URLs, and pp_format has the
ability to automatically add URL escapes for strings that the urlifier
gives it URLs for.

For example, given the format string:

  "%<#pragma pack%> has no effect with %<-fpack-struct%>"

with this patch GCC is able to automatically linkify the "#pragma pack"
text to
  https://gcc.gnu.org/onlinedocs/gcc/Structure-Layout-Pragmas.html
and the "-fpack-struct" text to:
  https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html#index-fpack-struct

and we don't have to modify the format string itself.

This is only done for the pp_format within
diagnostic_context::report_diagnostic i.e. just for the primary message
in each diagnostics, and not for other places within GCC that use pp
format internally.

"urlifier" is an abstract base class, with a GCC-specific subclass
implementing the logic for generating URLs into GCC's HTML
documentation via binary search in a data table.  This patch implements
the gcc_urlifier with a small table generated by hand; the data table in
this patch only covers various pragmas and the option referenced by the
above pragma message.

I have a followup patch that scripts the creation of this data by
directly scraping the output of "make html", thus automating all this,
and (I hope) minimizing the work of ensuring that documentation URLs
emitted by GCC match the generated documentation.

gcc/ChangeLog:
	* Makefile.in (GCC_OBJS): Add gcc-urlifier.o.
	(OBJS): Likewise.

gcc/c-family/ChangeLog:
	* c-pragma.cc:: (handle_pragma_push_options): Fix missing "GCC" in
	name of pragma in "junk" message.
	(handle_pragma_pop_options): Likewise.

gcc/ChangeLog:
	* diagnostic.cc: Include "pretty-print-urlifier.h".
	(diagnostic_context::initialize): Initialize m_urlifier.
	(diagnostic_context::finish): Clean up m_urlifier
	(diagnostic_report::diagnostic): m_urlifier to pp_format.
	* diagnostic.h (diagnostic_context::m_urlifier): New field.
	* gcc-urlifier.cc: New file.
	* gcc-urlifier.def: New file.
	* gcc-urlifier.h: New file.
	* gcc.cc: Include "gcc-urlifier.h".
	(driver::global_initializations): Initialize global_dc->m_urlifier.
	* pretty-print-urlifier.h: New file.
	* pretty-print.cc: Include "pretty-print-urlifier.h".
	(obstack_append_string): New.
	(urlify_quoted_string): New.
	(pp_format): Add "urlifier" param and use it to implement optional
	urlification of quoted text strings.
	(pp_output_formatted_text): Make buffer a const pointer.
	(selftest::pp_printf_with_urlifier): New.
	(selftest::test_urlification): New.
	(selftest::pretty_print_cc_tests): Call it.
	* pretty-print.h (class urlifier): New forward declaration.
	(pp_format): Add optional urlifier param.
	* selftest-run-tests.cc (selftest::run_tests): Call
	selftest::gcc_urlifier_cc_tests .
	* selftest.h (selftest::gcc_urlifier_cc_tests): New decl.
	* toplev.cc: Include "gcc-urlifier.h".
	(general_init): Initialize global_dc->m_urlifier.

Signed-off-by: David Malcolm <dmalcolm@redhat.com>
This commit is contained in:
David Malcolm 2023-11-03 21:46:53 -04:00
parent 8200cd97c9
commit c5db4d8ba5
14 changed files with 498 additions and 11 deletions

View file

@ -1286,7 +1286,7 @@ FORTRAN_TARGET_OBJS=@fortran_target_objs@
RUST_TARGET_OBJS=@rust_target_objs@
# Object files for gcc many-languages driver.
GCC_OBJS = gcc.o gcc-main.o ggc-none.o
GCC_OBJS = gcc.o gcc-main.o ggc-none.o gcc-urlifier.o
c-family-warn = $(STRICT_WARN)
@ -1459,6 +1459,7 @@ OBJS = \
function-tests.o \
fwprop.o \
gcc-rich-location.o \
gcc-urlifier.o \
gcse.o \
gcse-common.o \
ggc-common.o \

View file

@ -1208,7 +1208,7 @@ handle_pragma_push_options (cpp_reader *)
token = pragma_lex (&x);
if (token != CPP_EOF)
{
warning (OPT_Wpragmas, "junk at end of %<#pragma push_options%>");
warning (OPT_Wpragmas, "junk at end of %<#pragma GCC push_options%>");
return;
}
@ -1245,7 +1245,7 @@ handle_pragma_pop_options (cpp_reader *)
token = pragma_lex (&x);
if (token != CPP_EOF)
{
warning (OPT_Wpragmas, "junk at end of %<#pragma pop_options%>");
warning (OPT_Wpragmas, "junk at end of %<#pragma GCC pop_options%>");
return;
}

View file

@ -43,6 +43,7 @@ along with GCC; see the file COPYING3. If not see
#include "opts.h"
#include "cpplib.h"
#include "text-art/theme.h"
#include "pretty-print-urlifier.h"
#ifdef HAVE_TERMIOS_H
# include <termios.h>
@ -193,6 +194,7 @@ diagnostic_context::initialize (int n_opts)
m_option_state = nullptr;
m_option_name = nullptr;
m_get_option_url = nullptr;
m_urlifier = nullptr;
m_last_location = UNKNOWN_LOCATION;
m_last_module = nullptr;
m_client_aux_data = nullptr;
@ -350,6 +352,9 @@ diagnostic_context::finish ()
delete m_client_data_hooks;
m_client_data_hooks = nullptr;
}
delete m_urlifier;
m_urlifier = nullptr;
}
void
@ -1567,7 +1572,7 @@ diagnostic_context::report_diagnostic (diagnostic_info *diagnostic)
m_output_format->on_begin_group ();
m_diagnostic_groups.m_emission_count++;
pp_format (this->printer, &diagnostic->message);
pp_format (this->printer, &diagnostic->message, m_urlifier);
m_output_format->on_begin_diagnostic (diagnostic);
pp_output_formatted_text (this->printer);
if (m_show_cwe)

View file

@ -518,6 +518,10 @@ public:
particular option. */
char *(*m_get_option_url) (diagnostic_context *, int);
/* An optional hook for adding URLs to quoted text strings in
diagnostics. Only used for the main diagnostic message. */
urlifier *m_urlifier;
void (*m_print_path) (diagnostic_context *, const diagnostic_path *);
json::value *(*m_make_json_for_path) (diagnostic_context *,
const diagnostic_path *);

159
gcc/gcc-urlifier.cc Normal file
View file

@ -0,0 +1,159 @@
/* Automatic generation of links into GCC's documentation.
Copyright (C) 2023 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "pretty-print.h"
#include "pretty-print-urlifier.h"
#include "gcc-urlifier.h"
#include "selftest.h"
namespace {
/* Concrete subclass of urlifier for generating links into
GCC's HTML documentation. */
class gcc_urlifier : public urlifier
{
public:
char *get_url_for_quoted_text (const char *p, size_t sz) const final override;
const char *get_url_suffix_for_quoted_text (const char *p, size_t sz) const;
const char *get_url_suffix_for_quoted_text (const char *p) const;
private:
static char *
make_doc_url (const char *doc_url_suffix);
};
/* class gcc_urlifier : public urlifier. */
#define DOC_URL(QUOTED_TEXT, URL_SUFFIX) \
{ (QUOTED_TEXT), (URL_SUFFIX) }
const struct
{
const char *quoted_text;
const char *url_suffix;
} doc_urls[] = {
#include "gcc-urlifier.def"
};
char *
gcc_urlifier::get_url_for_quoted_text (const char *p, size_t sz) const
{
if (const char *url_suffix = get_url_suffix_for_quoted_text (p, sz))
return make_doc_url (url_suffix);
return nullptr;
}
const char *
gcc_urlifier::get_url_suffix_for_quoted_text (const char *p, size_t sz) const
{
/* Binary search. This assumes that the quoted_text fields of doc_urls
are in sorted order. */
int min = 0;
int max = ARRAY_SIZE (doc_urls) - 1;
while (true)
{
if (min > max)
return nullptr;
int midpoint = (min + max) / 2;
gcc_assert ((size_t)midpoint < ARRAY_SIZE (doc_urls));
int cmp = strncmp (p, doc_urls[midpoint].quoted_text, sz);
if (cmp == 0)
{
if (doc_urls[midpoint].quoted_text[sz] == '\0')
return doc_urls[midpoint].url_suffix;
else
max = midpoint - 1;
}
else if (cmp < 0)
max = midpoint - 1;
else
min = midpoint + 1;
}
return nullptr;
}
const char *
gcc_urlifier::get_url_suffix_for_quoted_text (const char *p) const
{
return get_url_suffix_for_quoted_text (p, strlen (p));
}
char *
gcc_urlifier::make_doc_url (const char *doc_url_suffix)
{
if (!doc_url_suffix)
return nullptr;
return concat (DOCUMENTATION_ROOT_URL, doc_url_suffix, nullptr);
}
} // anonymous namespace
urlifier *
make_gcc_urlifier ()
{
return new gcc_urlifier ();
}
#if CHECKING_P
namespace selftest {
/* Selftests. */
/* Run all of the selftests within this file. */
void
gcc_urlifier_cc_tests ()
{
/* Check that doc_urls.quoted_text is sorted. */
for (size_t idx = 1; idx < ARRAY_SIZE (doc_urls); idx++)
gcc_assert (strcmp (doc_urls[idx - 1].quoted_text,
doc_urls[idx].quoted_text)
< 0);
gcc_urlifier u;
ASSERT_EQ (u.get_url_suffix_for_quoted_text (""), nullptr);
ASSERT_EQ (u.get_url_suffix_for_quoted_text (")"), nullptr);
ASSERT_STREQ (u.get_url_suffix_for_quoted_text ("#pragma message"),
"gcc/Diagnostic-Pragmas.html");
// Incomplete prefix of a quoted_text
ASSERT_EQ (u.get_url_suffix_for_quoted_text ("#pragma mess"), nullptr);
/* Check that every element is findable. */
for (size_t idx = 0; idx < ARRAY_SIZE (doc_urls); idx++)
ASSERT_STREQ
(u.get_url_suffix_for_quoted_text (doc_urls[idx].quoted_text),
doc_urls[idx].url_suffix);
}
} // namespace selftest
#endif /* #if CHECKING_P */

20
gcc/gcc-urlifier.def Normal file
View file

@ -0,0 +1,20 @@
/* Keep this file sorted. */
DOC_URL ("#pragma GCC diagnostic", "gcc/Diagnostic-Pragmas.html"),
DOC_URL ("#pragma GCC diagnostic ignored_attributes", "gcc/Diagnostic-Pragmas.html"),
DOC_URL ("#pragma GCC ivdep", "gcc/Loop-Specific-Pragmas.html#index-pragma-GCC-ivdep"),
DOC_URL ("#pragma GCC novector", "gcc/Loop-Specific-Pragmas.html#index-pragma-GCC-novector"),
DOC_URL ("#pragma GCC optimize", "gcc/Function-Specific-Option-Pragmas.html#index-pragma-GCC-optimize"),
DOC_URL ("#pragma GCC pop_options", "gcc/Push_002fPop-Macro-Pragmas.html"),
DOC_URL ("#pragma GCC push_options", "gcc/Push_002fPop-Macro-Pragmas.html"),
DOC_URL ("#pragma GCC reset_options", "gcc/Function-Specific-Option-Pragmas.html#index-pragma-GCC-reset_005foptions"),
DOC_URL ("#pragma GCC target", "gcc/Function-Specific-Option-Pragmas.html#index-pragma-GCC-target"),
DOC_URL ("#pragma GCC unroll", "gcc/Loop-Specific-Pragmas.html#index-pragma-GCC-unroll-n"),
DOC_URL ("#pragma GCC visibility", "gcc/Visibility-Pragmas.html"),
DOC_URL ("#pragma GCC visibility pop", "gcc/Visibility-Pragmas.html"),
DOC_URL ("#pragma message", "gcc/Diagnostic-Pragmas.html"),
DOC_URL ("#pragma pack", "gcc/Structure-Layout-Pragmas.html"),
DOC_URL ("#pragma redefine_extname", "gcc/Symbol-Renaming-Pragmas.html"),
DOC_URL ("#pragma scalar_storage_order", "gcc/Structure-Layout-Pragmas.html"),
DOC_URL ("#pragma weak", "gcc/Weak-Pragmas.html"),
DOC_URL ("--version", "gcc/Overall-Options.html#index-version"),
DOC_URL ("-fpack-struct", "gcc/Code-Gen-Options.html#index-fpack-struct"),

26
gcc/gcc-urlifier.h Normal file
View file

@ -0,0 +1,26 @@
/* Automatic generation of links into GCC's documentation.
Copyright (C) 2023 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GCC is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#ifndef GCC_GCC_URLIFIER_H
#define GCC_GCC_URLIFIER_H
extern urlifier *make_gcc_urlifier ();
#endif /* GCC_GCC_URLIFIER_H */

View file

@ -46,6 +46,7 @@ compilation is specified by a string called a "spec". */
#include "spellcheck.h"
#include "opts-jobserver.h"
#include "common/common-target.h"
#include "gcc-urlifier.h"
#ifndef MATH_LIBRARY
#define MATH_LIBRARY "m"
@ -8291,6 +8292,7 @@ driver::global_initializations ()
diagnostic_initialize (global_dc, 0);
diagnostic_color_init (global_dc);
diagnostic_urls_init (global_dc);
global_dc->m_urlifier = make_gcc_urlifier ();
#ifdef GCC_DRIVER_HOST_INITIALIZATION
/* Perform host dependent initialization when needed. */

View file

@ -0,0 +1,33 @@
/* Copyright (C) 2023 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#ifndef GCC_PRETTY_PRINT_URLIFIER_H
#define GCC_PRETTY_PRINT_URLIFIER_H
/* Abstract base class for optional use in pp_format for adding URLs
to quoted text strings. */
class urlifier
{
public:
virtual ~urlifier () {}
virtual char *get_url_for_quoted_text (const char *p, size_t sz) const = 0;
};
#endif /* GCC_PRETTY_PRINT_URLIFIER_H */

View file

@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "intl.h"
#include "pretty-print.h"
#include "pretty-print-urlifier.h"
#include "diagnostic-color.h"
#include "diagnostic-event-id.h"
#include "selftest.h"
@ -1022,6 +1023,95 @@ pp_indent (pretty_printer *pp)
static const char *get_end_url_string (pretty_printer *);
/* Append STR to OSTACK, without a null-terminator. */
static void
obstack_append_string (obstack *ostack, const char *str)
{
obstack_grow (ostack, str, strlen (str));
}
/* Given quoted text starting at QUOTED_TEXT_START_IDX within PP's buffer,
potentially use URLIFIER (if non-null) to see if there's a URL for the
quoted text.
If so, replace the quoted part of the text in the buffer with a URLified
version of the text, using PP's settings.
For example, given this is the buffer:
"this is a test `hello world"
.................^~~~~~~~~~~
with the quoted text starting at the 'h' of "hello world", the buffer
becomes:
"this is a test `BEGIN_URL(URL)hello worldEND(URL)"
.................^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.................-----------replacement-----------
*/
static void
urlify_quoted_string (pretty_printer *pp,
const urlifier *urlifier,
size_t quoted_text_start_idx)
{
if (pp->url_format == URL_FORMAT_NONE)
return;
if (!urlifier)
return;
output_buffer * const buffer = pp_buffer (pp);
/* Get end of quoted string. */
const size_t close_quote_idx
= obstack_object_size (&buffer->chunk_obstack);
gcc_assert (close_quote_idx >= quoted_text_start_idx);
if (close_quote_idx == quoted_text_start_idx)
/* Empty quoted string; do nothing. */
return;
const size_t len = close_quote_idx - quoted_text_start_idx;
const char *start = (buffer->chunk_obstack.object_base
+ quoted_text_start_idx);
char *url = urlifier->get_url_for_quoted_text (start, len);
if (!url)
/* No URL for this quoted text; do nothing. */
return;
/* Stash a copy of the quoted text. */
char *text = xstrndup (start, len);
/* Replace quoted text... */
buffer->chunk_obstack.next_free -= len;
/* ...with URLified version of the text. */
/* Begin URL. */
switch (pp->url_format)
{
default:
case URL_FORMAT_NONE:
gcc_unreachable ();
case URL_FORMAT_ST:
obstack_append_string (&buffer->chunk_obstack,
"\33]8;;");
obstack_append_string (&buffer->chunk_obstack, url);
obstack_append_string (&buffer->chunk_obstack,
"\33\\");
break;
case URL_FORMAT_BEL:
obstack_append_string (&buffer->chunk_obstack,
"\33]8;;");
obstack_append_string (&buffer->chunk_obstack, url);
obstack_append_string (&buffer->chunk_obstack,
"\a");
break;
}
/* Add the text back. */
obstack_append_string (&buffer->chunk_obstack, text);
/* End URL. */
obstack_append_string (&buffer->chunk_obstack,
get_end_url_string (pp));
free (text);
free (url);
}
/* The following format specifiers are recognized as being client independent:
%d, %i: (signed) integer in base ten.
%u: unsigned integer in base ten.
@ -1064,12 +1154,25 @@ static const char *get_end_url_string (pretty_printer *);
/* Formatting phases 1 and 2: render TEXT->format_spec plus
text->m_args_ptr into a series of chunks in pp_buffer (PP)->args[].
Phase 3 is in pp_output_formatted_text. */
Phase 3 is in pp_output_formatted_text.
If URLIFIER is non-NULL, then use it to add URLs for quoted
strings, so that e.g.
"before %<quoted%> after"
with a URLIFIER that has a URL for "quoted" might be emitted as:
"before `BEGIN_URL(http://example.com)quotedEND_URL' after"
This only works for message fragments that are:
- quoted entirely in phase 1 (e.g. "%<this is quoted%>"), or
- quoted entirely in phase 2 (e.g. "%qs"),
but *not* in strings that use a mixture of both phases
(e.g. "%<this is a mixture: %s %>"). */
void
pp_format (pretty_printer *pp, text_info *text)
pp_format (pretty_printer *pp,
text_info *text,
const urlifier *urlifier)
{
output_buffer *buffer = pp_buffer (pp);
output_buffer * const buffer = pp_buffer (pp);
const char *p;
const char **args;
struct chunk_info *new_chunk_array;
@ -1079,6 +1182,9 @@ pp_format (pretty_printer *pp, text_info *text)
bool any_unnumbered = false, any_numbered = false;
const char **formatters[PP_NL_ARGMAX];
/* Keep track of location of last "%", if any. */
size_t quoted_text_start_idx = 0;
/* Allocate a new chunk structure. */
new_chunk_array = XOBNEW (&buffer->chunk_obstack, struct chunk_info);
new_chunk_array->prev = buffer->cur_chunk_array;
@ -1122,11 +1228,21 @@ pp_format (pretty_printer *pp, text_info *text)
= colorize_start (pp_show_color (pp), "quote");
obstack_grow (&buffer->chunk_obstack, colorstr, strlen (colorstr));
p++;
/* Stash offset of start of quoted string. */
quoted_text_start_idx
= obstack_object_size (&buffer->chunk_obstack);
continue;
}
case '>':
{
if (quoted_text_start_idx)
{
urlify_quoted_string (pp, urlifier, quoted_text_start_idx);
quoted_text_start_idx = 0;
}
const char *colorstr = colorize_stop (pp_show_color (pp));
obstack_grow (&buffer->chunk_obstack, colorstr, strlen (colorstr));
}
@ -1168,6 +1284,12 @@ pp_format (pretty_printer *pp, text_info *text)
obstack_1grow (&buffer->chunk_obstack, '\0');
gcc_assert (chunk < PP_NL_ARGMAX * 2);
args[chunk++] = XOBFINISH (&buffer->chunk_obstack, const char *);
/* We can't yet handle urlifying quoted strings that use
a combination of phase 1 and phase 2 e.g.
"did you mean %<-%s%>".
Stop any phase 1 quoted text if there are going to be any
phase 2 quoted chunks. */
quoted_text_start_idx = 0;
break;
}
@ -1270,6 +1392,7 @@ pp_format (pretty_printer *pp, text_info *text)
bool plus = false;
bool hash = false;
bool quote = false;
quoted_text_start_idx = 0;
/* We do not attempt to enforce any ordering on the modifier
characters. */
@ -1310,7 +1433,11 @@ pp_format (pretty_printer *pp, text_info *text)
gcc_assert (!wide || precision == 0);
if (quote)
pp_begin_quote (pp, pp_show_color (pp));
{
pp_begin_quote (pp, pp_show_color (pp));
quoted_text_start_idx
= obstack_object_size (&buffer->chunk_obstack);
}
switch (*p)
{
@ -1480,7 +1607,14 @@ pp_format (pretty_printer *pp, text_info *text)
}
if (quote)
pp_end_quote (pp, pp_show_color (pp));
{
if (quoted_text_start_idx)
{
urlify_quoted_string (pp, urlifier, quoted_text_start_idx);
quoted_text_start_idx = 0;
}
pp_end_quote (pp, pp_show_color (pp));
}
obstack_1grow (&buffer->chunk_obstack, '\0');
*formatters[argno] = XOBFINISH (&buffer->chunk_obstack, const char *);
@ -1507,7 +1641,7 @@ void
pp_output_formatted_text (pretty_printer *pp)
{
unsigned int chunk;
output_buffer *buffer = pp_buffer (pp);
output_buffer * const buffer = pp_buffer (pp);
struct chunk_info *chunk_array = buffer->cur_chunk_array;
const char **args = chunk_array->args;
@ -2640,6 +2774,101 @@ test_null_urls ()
}
}
/* Verify that URLification works as expected. */
static void
pp_printf_with_urlifier (pretty_printer *pp,
const urlifier *urlifier,
const char *msg, ...)
{
va_list ap;
va_start (ap, msg);
text_info text (msg, &ap, errno);
pp_format (pp, &text, urlifier);
pp_output_formatted_text (pp);
va_end (ap);
}
void
test_urlification ()
{
class test_urlifier : public urlifier
{
public:
char *
get_url_for_quoted_text (const char *p, size_t sz) const final override
{
if (!strncmp (p, "-foption", sz))
return xstrdup ("http://example.com");
return nullptr;
}
};
auto_fix_quotes fix_quotes;
const test_urlifier urlifier;
/* Uses of "%<" and "%>". */
{
{
pretty_printer pp;
pp.url_format = URL_FORMAT_NONE;
pp_printf_with_urlifier (&pp, &urlifier,
"foo %<-foption%> %<unrecognized%> bar");
ASSERT_STREQ ("foo `-foption' `unrecognized' bar",
pp_formatted_text (&pp));
}
{
pretty_printer pp;
pp.url_format = URL_FORMAT_ST;
pp_printf_with_urlifier (&pp, &urlifier,
"foo %<-foption%> %<unrecognized%> bar");
ASSERT_STREQ
("foo `\33]8;;http://example.com\33\\-foption\33]8;;\33\\'"
" `unrecognized' bar",
pp_formatted_text (&pp));
}
{
pretty_printer pp;
pp.url_format = URL_FORMAT_BEL;
pp_printf_with_urlifier (&pp, &urlifier,
"foo %<-foption%> %<unrecognized%> bar");
ASSERT_STREQ
("foo `\33]8;;http://example.com\a-foption\33]8;;\a'"
" `unrecognized' bar",
pp_formatted_text (&pp));
}
}
/* Use of "%qs". */
{
pretty_printer pp;
pp.url_format = URL_FORMAT_ST;
pp_printf_with_urlifier (&pp, &urlifier,
"foo %qs %qs bar",
"-foption", "unrecognized");
ASSERT_STREQ
("foo `\33]8;;http://example.com\33\\-foption\33]8;;\33\\'"
" `unrecognized' bar",
pp_formatted_text (&pp));
}
/* Mixed usage of %< and %s, where the quoted string is built between
a mixture of phase 1 and phase 2. */
{
pretty_printer pp;
pp.url_format = URL_FORMAT_ST;
pp_printf_with_urlifier (&pp, &urlifier,
"foo %<-f%s%> bar",
"option");
/* We don't support this, but make sure we don't crash. */
ASSERT_STREQ
("foo `-foption' bar",
pp_formatted_text (&pp));
}
}
/* Test multibyte awareness. */
static void test_utf8 ()
{
@ -2690,6 +2919,7 @@ pretty_print_cc_tests ()
test_prefixes_and_wrapping ();
test_urls ();
test_null_urls ();
test_urlification ();
test_utf8 ();
}

View file

@ -228,6 +228,8 @@ class format_postprocessor
/* True if colors should be shown. */
#define pp_show_color(PP) (PP)->show_color
class urlifier;
/* The data structure that contains the bare minimum required to do
proper pretty-printing. Clients may derived from this structure
and add additional fields they need. */
@ -404,7 +406,8 @@ extern void pp_verbatim (pretty_printer *, const char *, ...)
ATTRIBUTE_GCC_PPDIAG(2,3);
extern void pp_flush (pretty_printer *);
extern void pp_really_flush (pretty_printer *);
extern void pp_format (pretty_printer *, text_info *);
extern void pp_format (pretty_printer *, text_info *,
const urlifier * = nullptr);
extern void pp_output_formatted_text (pretty_printer *);
extern void pp_format_verbatim (pretty_printer *, text_info *);

View file

@ -120,6 +120,7 @@ selftest::run_tests ()
lang_hooks.run_lang_selftests ();
text_art_tests ();
gcc_urlifier_cc_tests ();
/* Run the analyzer selftests (if enabled). */
ana::selftest::run_analyzer_selftests ();

View file

@ -231,6 +231,7 @@ extern void et_forest_cc_tests ();
extern void fibonacci_heap_cc_tests ();
extern void fold_const_cc_tests ();
extern void function_tests_cc_tests ();
extern void gcc_urlifier_cc_tests ();
extern void ggc_tests_cc_tests ();
extern void gimple_cc_tests ();
extern void hash_map_tests_cc_tests ();

View file

@ -88,6 +88,7 @@ along with GCC; see the file COPYING3. If not see
#include "ipa-modref.h"
#include "ipa-param-manipulation.h"
#include "dbgcnt.h"
#include "gcc-urlifier.h"
#include "selftest.h"
@ -1048,6 +1049,7 @@ general_init (const char *argv0, bool init_signals)
global_dc->m_option_state = &global_options;
global_dc->m_option_name = option_name;
global_dc->m_get_option_url = get_option_url;
global_dc->m_urlifier = make_gcc_urlifier ();
if (init_signals)
{