From patchwork Sat Nov 4 01:59:55 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Malcolm X-Patchwork-Id: 1859202 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=KgPz+cz7; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SMgmm58f4z1yR2 for ; Sat, 4 Nov 2023 13:00:24 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 362F13858C60 for ; Sat, 4 Nov 2023 02:00:22 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id 2FFA73858D28 for ; Sat, 4 Nov 2023 02:00:07 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 2FFA73858D28 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 2FFA73858D28 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1699063211; cv=none; b=uoiGPCFF3VMIKmkQltyH3qgEg0/fOm8MBuW4z/PkoCf27ToT8gbl7/U4m+qRyk1xZdavsPTfc6Zn8Tq0svp8aQJdDd0hbC1wUoDj1SZhwT8+eHchpkLSl787TaiOEHOHq28zwAOQrLl0RwObyhAgv+TsWb4v1fep+SXeSiK003Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1699063211; c=relaxed/simple; bh=dbyD/kjyZZx+T4Hk8ZoUmIJ6xE/KoOHT+2kMirabxas=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=ii0UucDTppMBqA5Yo5Wv3xxWC+FkmuIirzt00EkXW8v8pS3Yl4TlxyinRyK8oaoqKwMgVGTrz7SG2UAYhIkv/h/SwnBEoHkop+cwx/tJXPZFwQS2blU1vU3NrKov/3CegkvAKs1FmPQHpa8hqBXuOwFIcD+0LiUTbeQIWK03jEc= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1699063206; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=XwZmVdyOfsbItW8w5YfN+vyNGpx+v02ElcAJJUpxOHA=; b=KgPz+cz7sSJKic9wg0k00oVf4n+dBKA3Il3f1RrdYOWcgIH53ytAziukciGZBRmTEeryTW f/pohnotuRIEkptXb3fBOkhOA5vmxkwFD/qcpy5m1MLZfYsa5OBL4kbeUxHzi31ftFfAxB lL1KRo/hbVfuXQKv2Aa/CY3DrRDbzHw= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-48-mZ-CejtuOIay1L_f3ooJNg-1; Fri, 03 Nov 2023 22:00:02 -0400 X-MC-Unique: mZ-CejtuOIay1L_f3ooJNg-1 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.rdu2.redhat.com [10.11.54.2]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id EAD64811E7B for ; Sat, 4 Nov 2023 02:00:01 +0000 (UTC) Received: from t14s.localdomain.com (unknown [10.22.8.62]) by smtp.corp.redhat.com (Postfix) with ESMTP id AED8C40C6EBC; Sat, 4 Nov 2023 02:00:01 +0000 (UTC) From: David Malcolm To: gcc-patches@gcc.gnu.org Cc: David Malcolm Subject: [pushed] diagnostics: add automatic URL-ification within messages Date: Fri, 3 Nov 2023 21:59:55 -0400 Message-Id: <20231104015955.2389603-1-dmalcolm@redhat.com> In-Reply-To: <20231102131933.2161191-4-dmalcolm@redhat.com> References: <20231102131933.2161191-4-dmalcolm@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.4.1 on 10.11.54.2 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org On Thu, 2023-11-02 at 09:19 -0400, David Malcolm wrote: [...snip...] I eliminated the dependency on the c-pragma.cc changes from this patch, updated it for diagnostic_context becoming a class, and pushed it to trunk as r14-5118-gc5db4d8ba5f3de (after re-testing it). For reference, here's what I pushed: 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. --- gcc/Makefile.in | 3 +- gcc/c-family/c-pragma.cc | 4 +- gcc/diagnostic.cc | 7 +- gcc/diagnostic.h | 4 + gcc/gcc-urlifier.cc | 159 +++++++++++++++++++++++ gcc/gcc-urlifier.def | 20 +++ gcc/gcc-urlifier.h | 26 ++++ gcc/gcc.cc | 2 + gcc/pretty-print-urlifier.h | 33 +++++ gcc/pretty-print.cc | 242 +++++++++++++++++++++++++++++++++++- gcc/pretty-print.h | 5 +- gcc/selftest-run-tests.cc | 1 + gcc/selftest.h | 1 + gcc/toplev.cc | 2 + 14 files changed, 498 insertions(+), 11 deletions(-) create mode 100644 gcc/gcc-urlifier.cc create mode 100644 gcc/gcc-urlifier.def create mode 100644 gcc/gcc-urlifier.h create mode 100644 gcc/pretty-print-urlifier.h diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 41ed8163cd8..ff77d3cdc64 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1279,7 +1279,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) @@ -1452,6 +1452,7 @@ OBJS = \ function-tests.o \ fwprop.o \ gcc-rich-location.o \ + gcc-urlifier.o \ gcse.o \ gcse-common.o \ ggc-common.o \ diff --git a/gcc/c-family/c-pragma.cc b/gcc/c-family/c-pragma.cc index df3e3e6b3b0..849f8ac8c8b 100644 --- a/gcc/c-family/c-pragma.cc +++ b/gcc/c-family/c-pragma.cc @@ -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; } diff --git a/gcc/diagnostic.cc b/gcc/diagnostic.cc index 4b92f5461be..e917e6ce4ac 100644 --- a/gcc/diagnostic.cc +++ b/gcc/diagnostic.cc @@ -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 @@ -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) diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h index 2def7bddce9..cf21558c7b2 100644 --- a/gcc/diagnostic.h +++ b/gcc/diagnostic.h @@ -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 *); diff --git a/gcc/gcc-urlifier.cc b/gcc/gcc-urlifier.cc new file mode 100644 index 00000000000..269246bc703 --- /dev/null +++ b/gcc/gcc-urlifier.cc @@ -0,0 +1,159 @@ +/* Automatic generation of links into GCC's documentation. + Copyright (C) 2023 Free Software Foundation, Inc. + Contributed by David Malcolm . + +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 +. */ + +#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 */ diff --git a/gcc/gcc-urlifier.def b/gcc/gcc-urlifier.def new file mode 100644 index 00000000000..360de930e9e --- /dev/null +++ b/gcc/gcc-urlifier.def @@ -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"), diff --git a/gcc/gcc-urlifier.h b/gcc/gcc-urlifier.h new file mode 100644 index 00000000000..614e1c64b94 --- /dev/null +++ b/gcc/gcc-urlifier.h @@ -0,0 +1,26 @@ +/* Automatic generation of links into GCC's documentation. + Copyright (C) 2023 Free Software Foundation, Inc. + Contributed by David Malcolm . + +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 +. */ + +#ifndef GCC_GCC_URLIFIER_H +#define GCC_GCC_URLIFIER_H + +extern urlifier *make_gcc_urlifier (); + +#endif /* GCC_GCC_URLIFIER_H */ diff --git a/gcc/gcc.cc b/gcc/gcc.cc index 0b7e07872cd..02464958f36 100644 --- a/gcc/gcc.cc +++ b/gcc/gcc.cc @@ -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. */ diff --git a/gcc/pretty-print-urlifier.h b/gcc/pretty-print-urlifier.h new file mode 100644 index 00000000000..bdb7fca00d4 --- /dev/null +++ b/gcc/pretty-print-urlifier.h @@ -0,0 +1,33 @@ +/* Copyright (C) 2023 Free Software Foundation, Inc. + Contributed by David Malcolm + +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 +. */ + +#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 */ diff --git a/gcc/pretty-print.cc b/gcc/pretty-print.cc index 80780cfd7b8..9a4827622dc 100644 --- a/gcc/pretty-print.cc +++ b/gcc/pretty-print.cc @@ -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 % 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. "%"), or + - quoted entirely in phase 2 (e.g. "%qs"), + but *not* in strings that use a mixture of both phases + (e.g. "%"). */ 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%> % 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%> % 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%> % 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 (); } diff --git a/gcc/pretty-print.h b/gcc/pretty-print.h index 8759f0def38..9ba2c0a406e 100644 --- a/gcc/pretty-print.h +++ b/gcc/pretty-print.h @@ -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 *); diff --git a/gcc/selftest-run-tests.cc b/gcc/selftest-run-tests.cc index e2fc8f84b1b..cb53e90ebaf 100644 --- a/gcc/selftest-run-tests.cc +++ b/gcc/selftest-run-tests.cc @@ -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 (); diff --git a/gcc/selftest.h b/gcc/selftest.h index 20d522afda4..b0a4142fe34 100644 --- a/gcc/selftest.h +++ b/gcc/selftest.h @@ -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 (); diff --git a/gcc/toplev.cc b/gcc/toplev.cc index d098a7c72a0..e39162a3e49 100644 --- a/gcc/toplev.cc +++ b/gcc/toplev.cc @@ -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) {