No functional change intended. Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu. Pushed to trunk as r16-1422-gf867196566c8aa.
gcc/ChangeLog: PR other/116792 * diagnostic-format-html.cc: Include "selftest-xml.h". (html_builder::make_element_for_diagnostic): Move... (class html_token_printer): ...from local to the function to the global namespace. (struct selftest::token_printer_test): New. (selftest::test_token_printer): New. (selftest::test_simple_log): Simplify using ASSERT_XML_PRINT_EQ. (selftest::test_metadata): Likewise. (selftest::diagnostic_format_html_cc_tests): Run the new test. * selftest-xml.h: New file. * xml.cc: Include "selftest-xml.h". (selftest::assert_xml_print_eq): New. (selftest::test_no_dtd): Simplify using ASSERT_XML_PRINT_EQ. (selftest::test_printer): Likewise. (selftest::test_attribute_ordering): Likewise. Signed-off-by: David Malcolm <dmalc...@redhat.com> --- gcc/diagnostic-format-html.cc | 219 ++++++++++++++++++++-------------- gcc/selftest-xml.h | 50 ++++++++ gcc/xml.cc | 29 +++-- 3 files changed, 198 insertions(+), 100 deletions(-) create mode 100644 gcc/selftest-xml.h diff --git a/gcc/diagnostic-format-html.cc b/gcc/diagnostic-format-html.cc index 22bf6b965df7..45d088150dd6 100644 --- a/gcc/diagnostic-format-html.cc +++ b/gcc/diagnostic-format-html.cc @@ -42,6 +42,7 @@ along with GCC; see the file COPYING3. If not see #include "xml.h" #include "xml-printer.h" #include "json.h" +#include "selftest-xml.h" // struct html_generation_options @@ -729,6 +730,82 @@ add_labelled_value (xml::printer &xp, xp.pop_tag ("div"); } +class html_token_printer : public token_printer +{ +public: + html_token_printer (xml::element &parent_element) + /* Ideally pp_token_lists that reach a token_printer should be + "balanced", but for now they can have mismatching pp_tokens + e.g. a begin_color without an end_color (PR other/120610). + Give html_token_printer its own xml::printer as a firewall to + limit the scope of the mismatches in the HTML. */ + : m_xp (parent_element, + /* Similarly we don't check that the popped tags match. */ + false) + { + } + void print_tokens (pretty_printer */*pp*/, + const pp_token_list &tokens) final override + { + /* Implement print_tokens by adding child elements to + m_parent_element. */ + for (auto iter = tokens.m_first; iter; iter = iter->m_next) + switch (iter->m_kind) + { + default: + gcc_unreachable (); + + case pp_token::kind::text: + { + pp_token_text *sub = as_a <pp_token_text *> (iter); + /* The value might be in the obstack, so we may need to + copy it. */ + m_xp.add_text (sub->m_value.get ()); + } + break; + + case pp_token::kind::begin_color: + { + pp_token_begin_color *sub = as_a <pp_token_begin_color *> (iter); + gcc_assert (sub->m_value.get ()); + m_xp.push_tag_with_class ("span", sub->m_value.get ()); + } + break; + + case pp_token::kind::end_color: + m_xp.pop_tag ("span"); + break; + + case pp_token::kind::begin_quote: + { + m_xp.add_text (open_quote); + m_xp.push_tag_with_class ("span", "gcc-quoted-text"); + } + break; + case pp_token::kind::end_quote: + { + m_xp.pop_tag ("span"); + m_xp.add_text (close_quote); + } + break; + + case pp_token::kind::begin_url: + { + pp_token_begin_url *sub = as_a <pp_token_begin_url *> (iter); + m_xp.push_tag ("a", true); + m_xp.set_attr ("href", sub->m_value.get ()); + } + break; + case pp_token::kind::end_url: + m_xp.pop_tag ("a"); + break; + } + } + +private: + xml::printer m_xp; +}; + /* Make a <div class="gcc-diagnostic"> for DIAGNOSTIC. If ALERT is true, make it be a PatternFly alert (see @@ -744,82 +821,6 @@ html_builder::make_element_for_diagnostic (const diagnostic_info &diagnostic, diagnostic_t orig_diag_kind, bool alert) { - class html_token_printer : public token_printer - { - public: - html_token_printer (xml::element &parent_element) - /* Ideally pp_token_lists that reach a token_printer should be - "balanced", but for now they can have mismatching pp_tokens - e.g. a begin_color without an end_color (PR other/120610). - Give html_token_printer its own xml::printer as a firewall to - limit the scope of the mismatches in the HTML. */ - : m_xp (parent_element, - /* Similarly we don't check that the popped tags match. */ - false) - { - } - void print_tokens (pretty_printer */*pp*/, - const pp_token_list &tokens) final override - { - /* Implement print_tokens by adding child elements to - m_parent_element. */ - for (auto iter = tokens.m_first; iter; iter = iter->m_next) - switch (iter->m_kind) - { - default: - gcc_unreachable (); - - case pp_token::kind::text: - { - pp_token_text *sub = as_a <pp_token_text *> (iter); - /* The value might be in the obstack, so we may need to - copy it. */ - m_xp.add_text (sub->m_value.get ()); - } - break; - - case pp_token::kind::begin_color: - { - pp_token_begin_color *sub = as_a <pp_token_begin_color *> (iter); - gcc_assert (sub->m_value.get ()); - m_xp.push_tag_with_class ("span", sub->m_value.get ()); - } - break; - - case pp_token::kind::end_color: - m_xp.pop_tag ("span"); - break; - - case pp_token::kind::begin_quote: - { - m_xp.add_text (open_quote); - m_xp.push_tag_with_class ("span", "gcc-quoted-text"); - } - break; - case pp_token::kind::end_quote: - { - m_xp.pop_tag ("span"); - m_xp.add_text (close_quote); - } - break; - - case pp_token::kind::begin_url: - { - pp_token_begin_url *sub = as_a <pp_token_begin_url *> (iter); - m_xp.push_tag ("a", true); - m_xp.set_attr ("href", sub->m_value.get ()); - } - break; - case pp_token::kind::end_url: - m_xp.pop_tag ("a"); - break; - } - } - - private: - xml::printer m_xp; - }; - const int diag_idx = m_next_diag_id++; std::string diag_id; { @@ -1329,6 +1330,53 @@ make_html_sink (diagnostic_context &context, namespace selftest { +/* Helper for writing tests of html_token_printer. + Printing to m_pp will appear as HTML within m_top_element, a <div>. */ + +struct token_printer_test +{ + token_printer_test () + : m_top_element ("div", true), + m_tok_printer (m_top_element) + { + m_pp.set_token_printer (&m_tok_printer); + } + + xml::element m_top_element; + html_token_printer m_tok_printer; + pretty_printer m_pp; +}; + +static void +test_token_printer () +{ + { + token_printer_test t; + pp_printf (&t.m_pp, "hello world"); + ASSERT_XML_PRINT_EQ + (t.m_top_element, + "<div>hello world</div>\n"); + } + + { + token_printer_test t; + pp_printf (&t.m_pp, "%qs: %qs", "foo", "bar"); + ASSERT_XML_PRINT_EQ + (t.m_top_element, + "<div>" + "`" + "<span class=\"gcc-quoted-text\">" + "foo" + "</span>" + "': `" + "<span class=\"gcc-quoted-text\">" + "bar" + "</span>" + "'" + "</div>\n"); + } +} + /* A subclass of html_output_format for writing selftests. The XML output is cached internally, rather than written out to a file. */ @@ -1394,10 +1442,8 @@ test_simple_log () const xml::document &doc = dc.get_document (); - pretty_printer pp; - doc.write_as_xml (&pp, 0, true); - ASSERT_STREQ - (pp_formatted_text (&pp), + ASSERT_XML_PRINT_EQ + (doc, ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" "<!DOCTYPE html\n" " PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n" @@ -1427,10 +1473,8 @@ test_metadata () diagnostic_metadata metadata; metadata.add_cwe (415); auto element = b.make_element_for_metadata (metadata); - pretty_printer pp; - element->write_as_xml (&pp, 0, true); - ASSERT_STREQ - (pp_formatted_text (&pp), + ASSERT_XML_PRINT_EQ + (*element, "<span class=\"gcc-metadata\">" "<span class=\"gcc-metadata-item\">" "[" @@ -1448,10 +1492,8 @@ test_metadata () "http://example.com"); metadata.add_rule (rule); auto element = b.make_element_for_metadata (metadata); - pretty_printer pp; - element->write_as_xml (&pp, 0, true); - ASSERT_STREQ - (pp_formatted_text (&pp), + ASSERT_XML_PRINT_EQ + (*element, "<span class=\"gcc-metadata\">" "<span class=\"gcc-metadata-item\">" "[" @@ -1470,6 +1512,7 @@ void diagnostic_format_html_cc_tests () { auto_fix_quotes fix_quotes; + test_token_printer (); test_simple_log (); test_metadata (); } diff --git a/gcc/selftest-xml.h b/gcc/selftest-xml.h new file mode 100644 index 000000000000..fd5c0afffd10 --- /dev/null +++ b/gcc/selftest-xml.h @@ -0,0 +1,50 @@ +/* Selftest support for XML. + Copyright (C) 2025 Free Software Foundation, Inc. + Contributed by David Malcolm <dmalc...@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_SELFTEST_XML_H +#define GCC_SELFTEST_XML_H + +#include "xml.h" + +/* The selftest code should entirely disappear in a production + configuration, hence we guard all of it with #if CHECKING_P. */ + +#if CHECKING_P + +namespace selftest { + +/* Assert that NODE written with indentation as xml source + equals EXPECTED_VALUE. + Use LOC for any failures. */ + +void +assert_xml_print_eq (const location &loc, + const xml::node &node, + const char *expected_value); +#define ASSERT_XML_PRINT_EQ(XML_NODE, EXPECTED_VALUE) \ + assert_xml_print_eq ((SELFTEST_LOCATION), \ + (XML_NODE), \ + (EXPECTED_VALUE)) + +} // namespace selftest + +#endif /* #if CHECKING_P */ + +#endif /* GCC_SELFTEST_XML_H */ diff --git a/gcc/xml.cc b/gcc/xml.cc index 9077c1ab1300..a23298bdd84b 100644 --- a/gcc/xml.cc +++ b/gcc/xml.cc @@ -28,6 +28,7 @@ along with GCC; see the file COPYING3. If not see #include "xml-printer.h" #include "pretty-print.h" #include "selftest.h" +#include "selftest-xml.h" namespace xml { @@ -316,14 +317,22 @@ printer::dump () const namespace selftest { +void +assert_xml_print_eq (const location &loc, + const xml::node &node, + const char *expected_value) +{ + pretty_printer pp; + node.write_as_xml (&pp, 0, true); + ASSERT_STREQ_AT (loc, pp_formatted_text (&pp), expected_value); +} + static void test_no_dtd () { xml::document doc; - pretty_printer pp; - doc.write_as_xml (&pp, 0, true); - ASSERT_STREQ - (pp_formatted_text (&pp), + ASSERT_XML_PRINT_EQ + (doc, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); } @@ -343,10 +352,8 @@ test_printer () xp.pop_tag ("bar"); xp.pop_tag ("foo"); - pretty_printer pp; - top.write_as_xml (&pp, 0, true); - ASSERT_STREQ - (pp_formatted_text (&pp), + ASSERT_XML_PRINT_EQ + (top, "<top>\n" " <foo>\n" " hello\n" @@ -378,10 +385,8 @@ test_attribute_ordering () xp.set_attr ("naseby", "1645"); xp.pop_tag ("alphabetical"); - pretty_printer pp; - top.write_as_xml (&pp, 0, true); - ASSERT_STREQ - (pp_formatted_text (&pp), + ASSERT_XML_PRINT_EQ + (top, "<top>\n" " <chronological maldon=\"991\" hastings=\"1066\" edgehill=\"1642\" naseby=\"1645\"/>\n" " <alphabetical edgehill=\"1642\" hastings=\"1066\" maldon=\"991\" naseby=\"1645\"/>\n" -- 2.26.3