/* 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