https://gcc.gnu.org/g:1233d79c1935f19104e76ba7aa842dc7ee6c2279

commit r16-1268-g1233d79c1935f19104e76ba7aa842dc7ee6c2279
Author: David Malcolm <dmalc...@redhat.com>
Date:   Fri Jun 6 13:41:27 2025 -0400

    diagnostics: move xml defs to a new xml.cc
    
    While prototyping new features I'm finding it helpful to use XML
    beyond the "experimental-html" diagnostics sink.  Move the
    implementation of the xml classes to their own file.
    
    No functional change intended.
    
    gcc/ChangeLog:
            * Makefile.in (OBJS-libcommon): Add xml.o.
            * diagnostic-format-html.cc (namespace xml): Move implementation
            to xml.cc
            (selftest::test_printer): Likewise.
            (selftest::test_attribute_ordering): Likewise.
            (selftest::diagnostic_format_html_cc_tests): Don't call the moved
            tests here; they will be called from xml_cc_tests in xml.cc.
            * selftest-run-tests.cc (selftest::run_tests): Call xml_cc_tests.
            * selftest.h (selftest::xml_cc_tests): New decl.
            * xml.cc: New file, based on material from
            diagnostic-format-html.cc.
    
    Signed-off-by: David Malcolm <dmalc...@redhat.com>

Diff:
---
 gcc/Makefile.in               |   1 +
 gcc/diagnostic-format-html.cc | 313 ------------------------------------
 gcc/selftest-run-tests.cc     |   1 +
 gcc/selftest.h                |   1 +
 gcc/xml.cc                    | 358 ++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 361 insertions(+), 313 deletions(-)

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 49869531bc8a..fe20b655477f 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1862,6 +1862,7 @@ OBJS-libcommon = diagnostic-spec.o diagnostic.o 
diagnostic-color.o \
        edit-context.o \
        pretty-print.o intl.o \
        json.o json-parsing.o \
+       xml.o \
        sbitmap.o \
        vec.o input.o hash-table.o ggc-none.o memory-block.o \
        selftest.o selftest-diagnostic.o sort.o \
diff --git a/gcc/diagnostic-format-html.cc b/gcc/diagnostic-format-html.cc
index 05d4273c2c61..076790bfff7a 100644
--- a/gcc/diagnostic-format-html.cc
+++ b/gcc/diagnostic-format-html.cc
@@ -49,256 +49,6 @@ html_generation_options::html_generation_options ()
 {
 }
 
-namespace xml {
-
-/* Disable warnings about quoting issues in the pp_xxx calls below
-   that (intentionally) don't follow GCC diagnostic conventions.  */
-#if __GNUC__ >= 10
-#  pragma GCC diagnostic push
-#  pragma GCC diagnostic ignored "-Wformat-diag"
-#endif
-
-
-/* Implementation.  */
-
-static void
-write_escaped_text (pretty_printer *pp, const char *text)
-{
-  gcc_assert (text);
-
-  for (const char *p = text; *p; ++p)
-    {
-      char ch = *p;
-      switch (ch)
-       {
-       default:
-         pp_character (pp, ch);
-         break;
-       case '\'':
-         pp_string (pp, "&apos;");
-         break;
-       case '"':
-         pp_string (pp, "&quot;");
-         break;
-       case '&':
-         pp_string (pp, "&amp;");
-         break;
-       case '<':
-         pp_string (pp, "&lt;");
-         break;
-       case '>':
-         pp_string (pp, "&gt;");
-         break;
-       }
-    }
-}
-
-/* struct node.  */
-
-void
-node::dump (FILE *out) const
-{
-  pretty_printer pp;
-  pp.set_output_stream (out);
-  write_as_xml (&pp, 0, true);
-  pp_flush (&pp);
-}
-
-/* struct text : public node.  */
-
-void
-text::write_as_xml (pretty_printer *pp, int depth, bool indent) const
-{
-  if (indent)
-    {
-      for (int i = 0; i < depth; ++i)
-       pp_string (pp, "  ");
-    }
-  write_escaped_text (pp, m_str.c_str ());
-  if (indent)
-    pp_newline (pp);
-}
-
-/* struct node_with_children : public node.  */
-
-void
-node_with_children::add_child (std::unique_ptr<node> node)
-{
-  gcc_assert (node.get ());
-  m_children.push_back (std::move (node));
-}
-
-void
-node_with_children::add_text (std::string str)
-{
-  // Consolidate runs of text
-  if (!m_children.empty ())
-    if (text *t = m_children.back ()->dyn_cast_text ())
-      {
-       t->m_str += std::move (str);
-       return;
-      }
-  add_child (std::make_unique <text> (std::move (str)));
-}
-
-
-/* struct document : public node_with_children.  */
-
-void
-document::write_as_xml (pretty_printer *pp, int depth, bool indent) const
-{
-  pp_string (pp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
-  pp_string (pp, "<!DOCTYPE html\n"
-            "     PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n"
-            "     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\";>");
-  if (indent)
-    pp_newline (pp);
-  for (auto &iter : m_children)
-    iter->write_as_xml (pp, depth, indent);
-}
-
-/* struct element : public node_with_children.  */
-
-void
-element::write_as_xml (pretty_printer *pp, int depth, bool indent) const
-{
-  if (indent)
-    {
-      for (int i = 0; i < depth; ++i)
-       pp_string (pp, "  ");
-    }
-
-  pp_printf (pp, "<%s", m_kind.c_str ());
-  for (auto &key : m_key_insertion_order)
-    {
-      auto iter = m_attributes.find (key);
-      if (iter != m_attributes.end ())
-       {
-         pp_printf (pp, " %s=\"", key.c_str ());
-         write_escaped_text (pp, iter->second.c_str ());
-         pp_string (pp, "\"");
-       }
-    }
-  if (m_children.empty ())
-    pp_string (pp, "/>");
-  else
-    {
-      const bool indent_children = m_preserve_whitespace ? false : indent;
-      pp_string (pp, ">");
-      if (indent_children)
-       pp_newline (pp);
-      for (auto &child : m_children)
-       child->write_as_xml (pp, depth + 1, indent_children);
-      if (indent_children)
-       {
-         for (int i = 0; i < depth; ++i)
-           pp_string (pp, "  ");
-       }
-      pp_printf (pp, "</%s>", m_kind.c_str ());
-    }
-
-  if (indent)
-    pp_newline (pp);
-}
-
-void
-element::set_attr (const char *name, std::string value)
-{
-  auto iter = m_attributes.find (name);
-  if (iter == m_attributes.end ())
-    m_key_insertion_order.push_back (name);
-  m_attributes[name] = std::move (value);
-}
-
-// struct raw : public node
-
-void
-raw::write_as_xml (pretty_printer *pp,
-                  int /*depth*/, bool /*indent*/) const
-{
-  pp_string (pp, m_xml_src.c_str ());
-}
-
-#if __GNUC__ >= 10
-#  pragma GCC diagnostic pop
-#endif
-
-// class printer
-
-printer::printer (element &insertion_point)
-{
-  m_open_tags.push_back (&insertion_point);
-}
-
-void
-printer::push_tag (std::string name,
-                  bool preserve_whitespace)
-{
-  push_element
-    (std::make_unique<element> (std::move (name),
-                               preserve_whitespace));
-}
-
-void
-printer::push_tag_with_class (std::string name, std::string class_,
-                             bool preserve_whitespace)
-{
-  auto new_element
-    = std::make_unique<element> (std::move (name),
-                                preserve_whitespace);
-  new_element->set_attr ("class", class_);
-  push_element (std::move (new_element));
-}
-
-void
-printer::pop_tag ()
-{
-  m_open_tags.pop_back ();
-}
-
-void
-printer::set_attr (const char *name, std::string value)
-{
-  m_open_tags.back ()->set_attr (name, value);
-}
-
-void
-printer::add_text (std::string text)
-{
-  element *parent = m_open_tags.back ();
-  parent->add_text (std::move (text));
-}
-
-void
-printer::add_raw (std::string text)
-{
-  element *parent = m_open_tags.back ();
-  parent->add_child (std::make_unique<xml::raw> (std::move (text)));
-}
-
-void
-printer::push_element (std::unique_ptr<element> new_element)
-{
-  element *parent = m_open_tags.back ();
-  m_open_tags.push_back (new_element.get ());
-  parent->add_child (std::move (new_element));
-}
-
-void
-printer::append (std::unique_ptr<node> new_node)
-{
-  element *parent = m_open_tags.back ();
-  parent->add_child (std::move (new_node));
-}
-
-element *
-printer::get_insertion_point () const
-{
-  return m_open_tags.back ();
-}
-
-} // namespace xml
-
 class html_builder;
 
 /* Concrete buffering implementation subclass for HTML output.  */
@@ -1288,67 +1038,6 @@ test_metadata ()
   }
 }
 
-static void
-test_printer ()
-{
-  xml::element top ("top", false);
-  xml::printer xp (top);
-  xp.push_tag ("foo");
-  xp.add_text ("hello");
-  xp.push_tag ("bar");
-  xp.set_attr ("size", "3");
-  xp.set_attr ("color", "red");
-  xp.add_text ("world");
-  xp.push_tag ("baz");
-  xp.pop_tag ();
-  xp.pop_tag ();
-  xp.pop_tag ();
-
-  pretty_printer pp;
-  top.write_as_xml (&pp, 0, true);
-  ASSERT_STREQ
-    (pp_formatted_text (&pp),
-     "<top>\n"
-     "  <foo>\n"
-     "    hello\n"
-     "    <bar size=\"3\" color=\"red\">\n"
-     "      world\n"
-     "      <baz/>\n"
-     "    </bar>\n"
-     "  </foo>\n"
-     "</top>\n");
-}
-
-// Verify that element attributes preserve insertion order.
-
-static void
-test_attribute_ordering ()
-{
-  xml::element top ("top", false);
-  xml::printer xp (top);
-  xp.push_tag ("chronological");
-  xp.set_attr ("maldon", "991");
-  xp.set_attr ("hastings", "1066");
-  xp.set_attr ("edgehill", "1642");
-  xp.set_attr ("naseby", "1645");
-  xp.pop_tag ();
-  xp.push_tag ("alphabetical");
-  xp.set_attr ("edgehill", "1642");
-  xp.set_attr ("hastings", "1066");
-  xp.set_attr ("maldon", "991");
-  xp.set_attr ("naseby", "1645");
-  xp.pop_tag ();
-
-  pretty_printer pp;
-  top.write_as_xml (&pp, 0, true);
-  ASSERT_STREQ
-    (pp_formatted_text (&pp),
-     "<top>\n"
-     "  <chronological maldon=\"991\" hastings=\"1066\" edgehill=\"1642\" 
naseby=\"1645\"/>\n"
-     "  <alphabetical edgehill=\"1642\" hastings=\"1066\" maldon=\"991\" 
naseby=\"1645\"/>\n"
-     "</top>\n");
-}
-
 /* Run all of the selftests within this file.  */
 
 void
@@ -1357,8 +1046,6 @@ diagnostic_format_html_cc_tests ()
   auto_fix_quotes fix_quotes;
   test_simple_log ();
   test_metadata ();
-  test_printer ();
-  test_attribute_ordering ();
 }
 
 } // namespace selftest
diff --git a/gcc/selftest-run-tests.cc b/gcc/selftest-run-tests.cc
index 0090e56bab6a..df49a67c9c91 100644
--- a/gcc/selftest-run-tests.cc
+++ b/gcc/selftest-run-tests.cc
@@ -80,6 +80,7 @@ selftest::run_tests ()
   optinfo_emit_json_cc_tests ();
   ordered_hash_map_tests_cc_tests ();
   splay_tree_cc_tests ();
+  xml_cc_tests ();
 
   /* Mid-level data structures.  */
   input_cc_tests ();
diff --git a/gcc/selftest.h b/gcc/selftest.h
index c5ea6de30137..94acf62b434e 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -276,6 +276,7 @@ extern void typed_splay_tree_cc_tests ();
 extern void vec_cc_tests ();
 extern void vec_perm_indices_cc_tests ();
 extern void wide_int_cc_tests ();
+extern void xml_cc_tests ();
 
 extern int num_passes;
 
diff --git a/gcc/xml.cc b/gcc/xml.cc
new file mode 100644
index 000000000000..e75884066f30
--- /dev/null
+++ b/gcc/xml.cc
@@ -0,0 +1,358 @@
+/* XML support for diagnostics.
+   Copyright (C) 2024-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/>.  */
+
+#include "config.h"
+#define INCLUDE_MAP
+#define INCLUDE_STRING
+#define INCLUDE_VECTOR
+#include "system.h"
+#include "coretypes.h"
+#include "xml.h"
+#include "xml-printer.h"
+#include "pretty-print.h"
+#include "selftest.h"
+
+namespace xml {
+
+/* Disable warnings about quoting issues in the pp_xxx calls below
+   that (intentionally) don't follow GCC diagnostic conventions.  */
+#if __GNUC__ >= 10
+#  pragma GCC diagnostic push
+#  pragma GCC diagnostic ignored "-Wformat-diag"
+#endif
+
+
+/* Implementation.  */
+
+static void
+write_escaped_text (pretty_printer *pp, const char *text)
+{
+  gcc_assert (text);
+
+  for (const char *p = text; *p; ++p)
+    {
+      char ch = *p;
+      switch (ch)
+       {
+       default:
+         pp_character (pp, ch);
+         break;
+       case '\'':
+         pp_string (pp, "&apos;");
+         break;
+       case '"':
+         pp_string (pp, "&quot;");
+         break;
+       case '&':
+         pp_string (pp, "&amp;");
+         break;
+       case '<':
+         pp_string (pp, "&lt;");
+         break;
+       case '>':
+         pp_string (pp, "&gt;");
+         break;
+       }
+    }
+}
+
+/* struct node.  */
+
+void
+node::dump (FILE *out) const
+{
+  pretty_printer pp;
+  pp.set_output_stream (out);
+  write_as_xml (&pp, 0, true);
+  pp_flush (&pp);
+}
+
+/* struct text : public node.  */
+
+void
+text::write_as_xml (pretty_printer *pp, int depth, bool indent) const
+{
+  if (indent)
+    {
+      for (int i = 0; i < depth; ++i)
+       pp_string (pp, "  ");
+    }
+  write_escaped_text (pp, m_str.c_str ());
+  if (indent)
+    pp_newline (pp);
+}
+
+/* struct node_with_children : public node.  */
+
+void
+node_with_children::add_child (std::unique_ptr<node> node)
+{
+  gcc_assert (node.get ());
+  m_children.push_back (std::move (node));
+}
+
+void
+node_with_children::add_text (std::string str)
+{
+  // Consolidate runs of text
+  if (!m_children.empty ())
+    if (text *t = m_children.back ()->dyn_cast_text ())
+      {
+       t->m_str += std::move (str);
+       return;
+      }
+  add_child (std::make_unique <text> (std::move (str)));
+}
+
+
+/* struct document : public node_with_children.  */
+
+void
+document::write_as_xml (pretty_printer *pp, int depth, bool indent) const
+{
+  pp_string (pp, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+  pp_string (pp, "<!DOCTYPE html\n"
+            "     PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n"
+            "     \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\";>");
+  if (indent)
+    pp_newline (pp);
+  for (auto &iter : m_children)
+    iter->write_as_xml (pp, depth, indent);
+}
+
+/* struct element : public node_with_children.  */
+
+void
+element::write_as_xml (pretty_printer *pp, int depth, bool indent) const
+{
+  if (indent)
+    {
+      for (int i = 0; i < depth; ++i)
+       pp_string (pp, "  ");
+    }
+
+  pp_printf (pp, "<%s", m_kind.c_str ());
+  for (auto &key : m_key_insertion_order)
+    {
+      auto iter = m_attributes.find (key);
+      if (iter != m_attributes.end ())
+       {
+         pp_printf (pp, " %s=\"", key.c_str ());
+         write_escaped_text (pp, iter->second.c_str ());
+         pp_string (pp, "\"");
+       }
+    }
+  if (m_children.empty ())
+    pp_string (pp, "/>");
+  else
+    {
+      const bool indent_children = m_preserve_whitespace ? false : indent;
+      pp_string (pp, ">");
+      if (indent_children)
+       pp_newline (pp);
+      for (auto &child : m_children)
+       child->write_as_xml (pp, depth + 1, indent_children);
+      if (indent_children)
+       {
+         for (int i = 0; i < depth; ++i)
+           pp_string (pp, "  ");
+       }
+      pp_printf (pp, "</%s>", m_kind.c_str ());
+    }
+
+  if (indent)
+    pp_newline (pp);
+}
+
+void
+element::set_attr (const char *name, std::string value)
+{
+  auto iter = m_attributes.find (name);
+  if (iter == m_attributes.end ())
+    m_key_insertion_order.push_back (name);
+  m_attributes[name] = std::move (value);
+}
+
+// struct raw : public node
+
+void
+raw::write_as_xml (pretty_printer *pp,
+                  int /*depth*/, bool /*indent*/) const
+{
+  pp_string (pp, m_xml_src.c_str ());
+}
+
+#if __GNUC__ >= 10
+#  pragma GCC diagnostic pop
+#endif
+
+// class printer
+
+printer::printer (element &insertion_point)
+{
+  m_open_tags.push_back (&insertion_point);
+}
+
+void
+printer::push_tag (std::string name,
+                  bool preserve_whitespace)
+{
+  push_element
+    (std::make_unique<element> (std::move (name),
+                               preserve_whitespace));
+}
+
+void
+printer::push_tag_with_class (std::string name, std::string class_,
+                             bool preserve_whitespace)
+{
+  auto new_element
+    = std::make_unique<element> (std::move (name),
+                                preserve_whitespace);
+  new_element->set_attr ("class", class_);
+  push_element (std::move (new_element));
+}
+
+void
+printer::pop_tag ()
+{
+  m_open_tags.pop_back ();
+}
+
+void
+printer::set_attr (const char *name, std::string value)
+{
+  m_open_tags.back ()->set_attr (name, value);
+}
+
+void
+printer::add_text (std::string text)
+{
+  element *parent = m_open_tags.back ();
+  parent->add_text (std::move (text));
+}
+
+void
+printer::add_raw (std::string text)
+{
+  element *parent = m_open_tags.back ();
+  parent->add_child (std::make_unique<xml::raw> (std::move (text)));
+}
+
+void
+printer::push_element (std::unique_ptr<element> new_element)
+{
+  element *parent = m_open_tags.back ();
+  m_open_tags.push_back (new_element.get ());
+  parent->add_child (std::move (new_element));
+}
+
+void
+printer::append (std::unique_ptr<node> new_node)
+{
+  element *parent = m_open_tags.back ();
+  parent->add_child (std::move (new_node));
+}
+
+element *
+printer::get_insertion_point () const
+{
+  return m_open_tags.back ();
+}
+
+} // namespace xml
+
+#if CHECKING_P
+
+namespace selftest {
+
+static void
+test_printer ()
+{
+  xml::element top ("top", false);
+  xml::printer xp (top);
+  xp.push_tag ("foo");
+  xp.add_text ("hello");
+  xp.push_tag ("bar");
+  xp.set_attr ("size", "3");
+  xp.set_attr ("color", "red");
+  xp.add_text ("world");
+  xp.push_tag ("baz");
+  xp.pop_tag ();
+  xp.pop_tag ();
+  xp.pop_tag ();
+
+  pretty_printer pp;
+  top.write_as_xml (&pp, 0, true);
+  ASSERT_STREQ
+    (pp_formatted_text (&pp),
+     "<top>\n"
+     "  <foo>\n"
+     "    hello\n"
+     "    <bar size=\"3\" color=\"red\">\n"
+     "      world\n"
+     "      <baz/>\n"
+     "    </bar>\n"
+     "  </foo>\n"
+     "</top>\n");
+}
+
+// Verify that element attributes preserve insertion order.
+
+static void
+test_attribute_ordering ()
+{
+  xml::element top ("top", false);
+  xml::printer xp (top);
+  xp.push_tag ("chronological");
+  xp.set_attr ("maldon", "991");
+  xp.set_attr ("hastings", "1066");
+  xp.set_attr ("edgehill", "1642");
+  xp.set_attr ("naseby", "1645");
+  xp.pop_tag ();
+  xp.push_tag ("alphabetical");
+  xp.set_attr ("edgehill", "1642");
+  xp.set_attr ("hastings", "1066");
+  xp.set_attr ("maldon", "991");
+  xp.set_attr ("naseby", "1645");
+  xp.pop_tag ();
+
+  pretty_printer pp;
+  top.write_as_xml (&pp, 0, true);
+  ASSERT_STREQ
+    (pp_formatted_text (&pp),
+     "<top>\n"
+     "  <chronological maldon=\"991\" hastings=\"1066\" edgehill=\"1642\" 
naseby=\"1645\"/>\n"
+     "  <alphabetical edgehill=\"1642\" hastings=\"1066\" maldon=\"991\" 
naseby=\"1645\"/>\n"
+     "</top>\n");
+}
+
+/* Run all of the selftests within this file.  */
+
+void
+xml_cc_tests ()
+{
+  test_printer ();
+  test_attribute_ordering ();
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */

Reply via email to