/* HTML output for diagnostics. Copyright (C) 2024-2025 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" #define INCLUDE_MAP #define INCLUDE_STRING #define INCLUDE_VECTOR #include "system.h" #include "coretypes.h" #include "diagnostic.h" #include "diagnostic-metadata.h" #include "diagnostic-format.h" #include "diagnostic-format-html.h" #include "diagnostic-format-text.h" #include "diagnostic-output-file.h" #include "diagnostic-buffer.h" #include "diagnostic-path.h" #include "diagnostic-client-data-hooks.h" #include "selftest.h" #include "selftest-diagnostic.h" #include "pretty-print-format-impl.h" #include "pretty-print-urlifier.h" #include "edit-context.h" #include "intl.h" #include "xml.h" #include "xml-printer.h" #include "diagnostic-state.h" #include "graphviz.h" #include "json.h" #include "selftest-xml.h" // struct html_generation_options html_generation_options::html_generation_options () : m_css (true), m_javascript (true), m_show_state_diagrams (false), m_show_state_diagram_xml (false), m_show_state_diagram_dot_src (false) { } class html_builder; /* Concrete buffering implementation subclass for HTML output. */ class diagnostic_html_format_buffer : public diagnostic_per_format_buffer { public: friend class html_builder; friend class html_output_format; diagnostic_html_format_buffer (html_builder &builder) : m_builder (builder) {} void dump (FILE *out, int indent) const final override; bool empty_p () const final override; void move_to (diagnostic_per_format_buffer &dest) final override; void clear () final override; void flush () final override; void add_result (std::unique_ptr result) { m_results.push_back (std::move (result)); } private: html_builder &m_builder; std::vector> m_results; }; /* A class for managing HTML output of diagnostics. Implemented: - message text Known limitations/missing functionality: - title for page - file/line/column - error vs warning - CWEs - rules - fix-it hints - paths */ class html_builder { public: friend class diagnostic_html_format_buffer; html_builder (diagnostic_context &context, pretty_printer &pp, const line_maps *line_maps, const html_generation_options &html_gen_opts); void set_main_input_filename (const char *name); void on_report_diagnostic (const diagnostic_info &diagnostic, diagnostic_t orig_diag_kind, diagnostic_html_format_buffer *buffer); void emit_diagram (const diagnostic_diagram &diagram); void end_group (); std::unique_ptr take_current_diagnostic () { return std::move (m_cur_diagnostic_element); } void flush_to_file (FILE *outf); const xml::document &get_document () const { return *m_document; } void set_printer (pretty_printer &pp) { m_printer = &pp; } std::unique_ptr make_element_for_metadata (const diagnostic_metadata &metadata); std::unique_ptr make_element_for_patch (const diagnostic_info &diagnostic); void add_focus_id (std::string focus_id) { m_ui_focus_ids.append_string (focus_id.c_str ()); } std::unique_ptr maybe_make_state_diagram (const diagnostic_event &event); private: void add_stylesheet (std::string url); std::unique_ptr make_element_for_diagnostic (const diagnostic_info &diagnostic, diagnostic_t orig_diag_kind, bool alert); std::unique_ptr make_metadata_element (label_text label, label_text url); void add_at_nesting_level (size_t nesting_level, std::unique_ptr child_diag_element); void push_nesting_level (); void pop_nesting_level (); diagnostic_context &m_context; pretty_printer *m_printer; const line_maps *m_line_maps; html_generation_options m_html_gen_opts; const logical_location_manager *m_logical_loc_mgr; std::unique_ptr m_document; xml::element *m_head_element; xml::element *m_title_element; xml::element *m_diagnostics_element; std::unique_ptr m_cur_diagnostic_element; std::vector m_cur_nesting_levels; int m_next_diag_id; // for handing out unique IDs json::array m_ui_focus_ids; logical_location m_last_logical_location; location_t m_last_location; expanded_location m_last_expanded_location; }; static std::unique_ptr make_div (std::string class_) { auto div = std::make_unique ("div", false); div->set_attr ("class", std::move (class_)); return div; } static std::unique_ptr make_span (std::string class_) { auto span = std::make_unique ("span", true); span->set_attr ("class", std::move (class_)); return span; } /* class diagnostic_html_format_buffer : public diagnostic_per_format_buffer. */ void diagnostic_html_format_buffer::dump (FILE *out, int indent) const { fprintf (out, "%*sdiagnostic_html_format_buffer:\n", indent, ""); int idx = 0; for (auto &result : m_results) { fprintf (out, "%*sresult[%i]:\n", indent + 2, "", idx); result->dump (out); fprintf (out, "\n"); ++idx; } } bool diagnostic_html_format_buffer::empty_p () const { return m_results.empty (); } void diagnostic_html_format_buffer::move_to (diagnostic_per_format_buffer &base) { diagnostic_html_format_buffer &dest = static_cast (base); for (auto &&result : m_results) dest.m_results.push_back (std::move (result)); m_results.clear (); } void diagnostic_html_format_buffer::clear () { m_results.clear (); } void diagnostic_html_format_buffer::flush () { for (auto &&result : m_results) m_builder.m_diagnostics_element->add_child (std::move (result)); m_results.clear (); } /* class html_builder. */ /* Style information for writing out HTML paths. Colors taken from https://pf3.patternfly.org/v3/styles/color-palette/ */ static const char * const HTML_STYLE = (" \n"); /* A little JavaScript for ease of navigation. Keys j/k move forward and backward cyclically through a list of focus ids (written out in another