diff options
Diffstat (limited to 'gcc/diagnostic-format-html.cc')
-rw-r--r-- | gcc/diagnostic-format-html.cc | 660 |
1 files changed, 555 insertions, 105 deletions
diff --git a/gcc/diagnostic-format-html.cc b/gcc/diagnostic-format-html.cc index ea2dbbb..45d0881 100644 --- a/gcc/diagnostic-format-html.cc +++ b/gcc/diagnostic-format-html.cc @@ -31,6 +31,8 @@ along with GCC; see the file COPYING3. If not see #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" @@ -40,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 @@ -104,6 +107,9 @@ public: 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); @@ -136,25 +142,45 @@ public: } private: + void + add_stylesheet (std::string url); + std::unique_ptr<xml::element> make_element_for_diagnostic (const diagnostic_info &diagnostic, - diagnostic_t orig_diag_kind); + diagnostic_t orig_diag_kind, + bool alert); std::unique_ptr<xml::element> make_metadata_element (label_text label, label_text url); + void + add_at_nesting_level (size_t nesting_level, + std::unique_ptr<xml::element> 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<xml::document> m_document; xml::element *m_head_element; + xml::element *m_title_element; xml::element *m_diagnostics_element; std::unique_ptr<xml::element> m_cur_diagnostic_element; + std::vector<xml::element *> 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<xml::element> @@ -233,8 +259,10 @@ static const char * const HTML_STYLE " .ruler { color: red;\n" " white-space: pre; }\n" " .source { color: blue;\n" + " background-color: white;\n" " white-space: pre; }\n" " .annotation { color: green;\n" + " background-color: white;\n" " white-space: pre; }\n" " .linenum-gap { text-align: center;\n" " border-top: 1px solid black;\n" @@ -265,6 +293,8 @@ static const char * const HTML_STYLE " font-weight: bold; }\n" " .highlight-b { color: #3f9c35;\n" // pf-green-400 " font-weight: bold; }\n" + " .gcc-quoted-text { font-weight: bold;\n" + " font-family: mono; }\n" " </style>\n"); /* A little JavaScript for ease of navigation. @@ -347,12 +377,19 @@ html_builder::html_builder (diagnostic_context &context, m_printer (&pp), m_line_maps (line_maps), m_html_gen_opts (html_gen_opts), + m_logical_loc_mgr (nullptr), m_head_element (nullptr), + m_title_element (nullptr), m_diagnostics_element (nullptr), - m_next_diag_id (0) + m_next_diag_id (0), + m_last_location (UNKNOWN_LOCATION), + m_last_expanded_location ({}) { gcc_assert (m_line_maps); + if (auto client_data_hooks = context.get_client_data_hooks ()) + m_logical_loc_mgr = client_data_hooks->get_logical_location_manager (); + m_document = std::make_unique<xml::document> (); m_document->m_doctypedecl = std::make_unique<html_doctypedecl> (); { @@ -367,17 +404,22 @@ html_builder::html_builder (diagnostic_context &context, m_head_element = xp.get_insertion_point (); { xml::auto_print_element title (xp, "title", true); - xp.add_text ("Title goes here"); + m_title_element = xp.get_insertion_point (); } + if (m_html_gen_opts.m_css) - xp.add_raw (HTML_STYLE); + { + add_stylesheet ("https://cdnjs.cloudflare.com/ajax/libs/patternfly/3.24.0/css/patternfly.min.css"); + add_stylesheet ("https://cdnjs.cloudflare.com/ajax/libs/patternfly/3.24.0/css/patternfly-additions.min.css"); + xp.add_raw (HTML_STYLE); + } if (m_html_gen_opts.m_javascript) { xp.push_tag ("script"); /* Escaping rules are different for HTML <script> elements, so add the script "raw" for now. */ xp.add_raw (HTML_SCRIPT); - xp.pop_tag (); // script + xp.pop_tag ("script"); } } @@ -392,6 +434,29 @@ html_builder::html_builder (diagnostic_context &context, } } +void +html_builder::set_main_input_filename (const char *name) +{ + gcc_assert (m_title_element); + if (name) + { + m_title_element->m_children.clear (); + m_title_element->add_text (name); + } +} + +void +html_builder::add_stylesheet (std::string url) +{ + gcc_assert (m_head_element); + + xml::printer xp (*m_head_element); + xp.push_tag ("link", false); + xp.set_attr ("rel", "stylesheet"); + xp.set_attr ("type", "text/css"); + xp.set_attr ("href", std::move (url)); +} + /* Implementation of "on_report_diagnostic" for HTML output. */ void @@ -409,8 +474,14 @@ html_builder::on_report_diagnostic (const diagnostic_info &diagnostic, fnotice (stderr, "Internal compiler error:\n"); } + const int nesting_level = m_context.get_diagnostic_nesting_level (); + bool alert = true; + if (m_cur_diagnostic_element && nesting_level > 0) + alert = false; + if (!m_cur_diagnostic_element) + m_last_logical_location = logical_location (); auto diag_element - = make_element_for_diagnostic (diagnostic, orig_diag_kind); + = make_element_for_diagnostic (diagnostic, orig_diag_kind, alert); if (buffer) { gcc_assert (!m_cur_diagnostic_element); @@ -419,14 +490,79 @@ html_builder::on_report_diagnostic (const diagnostic_info &diagnostic, else { if (m_cur_diagnostic_element) - /* Nested diagnostic. */ - m_cur_diagnostic_element->add_child (std::move (diag_element)); + { + /* Nested diagnostic. */ + gcc_assert (nesting_level >= 0); + add_at_nesting_level (nesting_level, std::move (diag_element)); + } else /* Top-level diagnostic. */ - m_cur_diagnostic_element = std::move (diag_element); + { + m_cur_diagnostic_element = std::move (diag_element); + m_cur_nesting_levels.clear (); + } } } +// For ease of comparison with experimental-nesting-show-levels=yes + +static void +add_nesting_level_attr (xml::element &element, + int nesting_level) +{ + element.set_attr ("nesting-level", std::to_string (nesting_level)); +} + +void +html_builder:: +add_at_nesting_level (size_t nesting_level, + std::unique_ptr<xml::element> child_diag_element) +{ + gcc_assert (m_cur_diagnostic_element); + while (nesting_level > m_cur_nesting_levels.size ()) + push_nesting_level (); + while (nesting_level < m_cur_nesting_levels.size ()) + pop_nesting_level (); + + if (nesting_level > 0) + { + gcc_assert (!m_cur_nesting_levels.empty ()); + auto current_nesting_level = m_cur_nesting_levels.back (); + xml::printer xp (*current_nesting_level); + xp.push_tag ("li"); + add_nesting_level_attr (*xp.get_insertion_point (), + m_cur_nesting_levels.size ()); + xp.append (std::move (child_diag_element)); + xp.pop_tag ("li"); + } + else + m_cur_diagnostic_element->add_child (std::move (child_diag_element)); +} + +void +html_builder::push_nesting_level () +{ + gcc_assert (m_cur_diagnostic_element); + auto new_nesting_level = std::make_unique<xml::element> ("ul", false); + add_nesting_level_attr (*new_nesting_level, + m_cur_nesting_levels.size () + 1); + xml::element *current_nesting_level = nullptr; + if (!m_cur_nesting_levels.empty ()) + current_nesting_level = m_cur_nesting_levels.back (); + m_cur_nesting_levels.push_back (new_nesting_level.get ()); + if (current_nesting_level) + current_nesting_level->add_child (std::move (new_nesting_level)); + else + m_cur_diagnostic_element->add_child (std::move (new_nesting_level)); +} + +void +html_builder::pop_nesting_level () +{ + gcc_assert (m_cur_diagnostic_element); + m_cur_nesting_levels.pop_back (); +} + /* Custom subclass of html_label_writer. Wrap labels within a <span> element, supplying them with event IDs. Add the IDs to the list of focus IDs. */ @@ -456,7 +592,7 @@ public: void end_label () final override { - m_xp.pop_tag (); // span + m_xp.pop_tag ("span"); // from begin_label } private: @@ -466,81 +602,225 @@ private: int m_next_event_idx; }; -std::unique_ptr<xml::element> -html_builder::make_element_for_diagnostic (const diagnostic_info &diagnostic, - diagnostic_t orig_diag_kind) +/* See https://pf3.patternfly.org/v3/pattern-library/widgets/#alerts */ +static const char * +get_pf_class_for_alert_div (diagnostic_t diag_kind) { - class html_token_printer : public token_printer - { - public: - html_token_printer (xml::printer &xp) - : m_xp (xp) + switch (diag_kind) + { + case DK_DEBUG: + case DK_NOTE: + return "alert alert-info"; + + case DK_ANACHRONISM: + case DK_WARNING: + return "alert alert-warning"; + + case DK_ERROR: + case DK_SORRY: + case DK_ICE: + case DK_ICE_NOBT: + case DK_FATAL: + return "alert alert-danger"; + + default: + gcc_unreachable (); + } +} + +static const char * +get_pf_class_for_alert_icon (diagnostic_t diag_kind) +{ + switch (diag_kind) { + case DK_DEBUG: + case DK_NOTE: + return "pficon pficon-info"; + + case DK_ANACHRONISM: + case DK_WARNING: + return "pficon pficon-warning-triangle-o"; + + case DK_ERROR: + case DK_SORRY: + case DK_ICE: + case DK_ICE_NOBT: + case DK_FATAL: + return "pficon pficon-error-circle-o"; + + default: + gcc_unreachable (); } - void print_tokens (pretty_printer */*pp*/, - const pp_token_list &tokens) final override +} + +static const char * +get_label_for_logical_location_kind (enum logical_location_kind kind) +{ + switch (kind) { - /* 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 logical_location_kind::unknown: + return nullptr; + + /* Kinds within executable code. */ + case logical_location_kind::function: + return "Function"; + case logical_location_kind::member: + return "Member"; + case logical_location_kind::module_: + return "Module"; + case logical_location_kind::namespace_: + return "Namespace"; + case logical_location_kind::type: + return "Type"; + case logical_location_kind::return_type: + return "Return type"; + case logical_location_kind::parameter: + return "Parameter"; + case logical_location_kind::variable: + return "Variable"; + + /* Kinds within XML or HTML documents. */ + case logical_location_kind::element: + return "Element"; + case logical_location_kind::attribute: + return "Attribute"; + case logical_location_kind::text: + return "Text"; + case logical_location_kind::comment: + return "Comment"; + case logical_location_kind::processing_instruction: + return "Processing Instruction"; + case logical_location_kind::dtd: + return "DTD"; + case logical_location_kind::declaration: + return "Declaration"; + + /* Kinds within JSON documents. */ + case logical_location_kind::object: + return "Object"; + case logical_location_kind::array: + return "Array"; + case logical_location_kind::property: + return "Property"; + case logical_location_kind::value: + return "Value"; + } +} + +static void +add_labelled_value (xml::printer &xp, + std::string id, + std::string label, + std::string value, + bool quote_value) +{ + xp.push_tag ("div", true); + xp.set_attr ("id", id); + xp.push_tag ("span"); + xp.add_text (label); + xp.add_text (" "); + xp.pop_tag ("span"); + xp.push_tag ("span"); + if (quote_value) + xp.set_attr ("class", "gcc-quoted-text"); + xp.add_text (std::move (value)); + xp.pop_tag ("span"); + 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: { - 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 ()); + 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; + 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::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 (); - 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 (); - m_xp.add_text (close_quote); - } - 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 (); - 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; - }; +private: + xml::printer m_xp; +}; - auto diag_element = make_div ("gcc-diagnostic"); +/* Make a <div class="gcc-diagnostic"> for DIAGNOSTIC. + + If ALERT is true, make it be a PatternFly alert (see + https://pf3.patternfly.org/v3/pattern-library/widgets/#alerts) and + show severity text (e.g. "error: "). + If ALERT is false, don't show the severity text and don't show + the filename if it's the same as the previous diagnostic within the + diagnostic group. */ + +std::unique_ptr<xml::element> +html_builder::make_element_for_diagnostic (const diagnostic_info &diagnostic, + diagnostic_t orig_diag_kind, + bool alert) +{ const int diag_idx = m_next_diag_id++; std::string diag_id; { @@ -548,30 +828,75 @@ html_builder::make_element_for_diagnostic (const diagnostic_info &diagnostic, pp_printf (&pp, "gcc-diag-%i", diag_idx); diag_id = pp_formatted_text (&pp); } - diag_element->set_attr ("id", diag_id); // TODO: might be nice to emulate the text output format, but colorize it - auto message_span = make_span ("gcc-message"); - std::string message_span_id (diag_id + "-message"); - message_span->set_attr ("id", message_span_id); - add_focus_id (message_span_id); + /* See https://pf3.patternfly.org/v3/pattern-library/widgets/#alerts + which has this example: +<div class="alert alert-danger"> + <span class="pficon pficon-error-circle-o"></span> + <strong>Hey there is a problem!</strong> Yeah this is really messed up and you should <a href="#" class="alert-link">know about it</a>. +</div> + */ + auto diag_element = make_div ("gcc-diagnostic"); + diag_element->set_attr ("id", diag_id); + if (alert) + diag_element->set_attr ("class", + get_pf_class_for_alert_div (diagnostic.kind)); + + xml::printer xp (*diag_element.get ()); + const size_t depth_within_alert_div = 1; + + gcc_assert (xp.get_num_open_tags () == depth_within_alert_div); + + if (alert) + { + xp.push_tag_with_class ("span", + get_pf_class_for_alert_icon (diagnostic.kind), + true); + xp.add_text (" "); + xp.pop_tag ("span"); + } + + // The rest goes in the <div>... + gcc_assert (xp.get_num_open_tags () == depth_within_alert_div); + + xp.push_tag_with_class ("div", "gcc-message", true); + std::string message_alert_id (diag_id + "-message"); + xp.set_attr ("id", message_alert_id); + add_focus_id (message_alert_id); + + const size_t depth_within_message_div = depth_within_alert_div + 1; + gcc_assert (xp.get_num_open_tags () == depth_within_message_div); + + // Severity e.g. "warning: " + bool show_severity = true; + if (!alert) + show_severity = false; + if (show_severity) + { + xp.push_tag ("strong"); + xp.add_text (_(get_diagnostic_kind_text (diagnostic.kind))); + xp.pop_tag ("strong"); + xp.add_text (" "); + } - xml::printer xp (*message_span.get ()); - html_token_printer tok_printer (xp); + // Add the message itself: + html_token_printer tok_printer (*xp.get_insertion_point ()); m_printer->set_token_printer (&tok_printer); pp_output_formatted_text (m_printer, m_context.get_urlifier ()); m_printer->set_token_printer (nullptr); pp_clear_output_area (m_printer); - diag_element->add_child (std::move (message_span)); + // Add any metadata as a suffix to the message if (diagnostic.metadata) { - diag_element->add_text (" "); - diag_element->add_child - (make_element_for_metadata (*diagnostic.metadata)); + xp.add_text (" "); + xp.append (make_element_for_metadata (*diagnostic.metadata)); } + // Add any option as a suffix to the message + label_text option_text = label_text::take (m_context.make_option_name (diagnostic.option_id, orig_diag_kind, diagnostic.kind)); @@ -580,7 +905,7 @@ html_builder::make_element_for_diagnostic (const diagnostic_info &diagnostic, label_text option_url = label_text::take (m_context.make_option_url (diagnostic.option_id)); - diag_element->add_text (" "); + xp.add_text (" "); auto option_span = make_span ("gcc-option"); option_span->add_text ("["); { @@ -595,35 +920,110 @@ html_builder::make_element_for_diagnostic (const diagnostic_info &diagnostic, option_span->add_text (option_text.get ()); option_span->add_text ("]"); } - diag_element->add_child (std::move (option_span)); + xp.append (std::move (option_span)); + } + + gcc_assert (xp.get_num_open_tags () == depth_within_message_div); + + xp.pop_tag ("div"); + + gcc_assert (xp.get_num_open_tags () == depth_within_alert_div); + + /* Show any logical location. */ + if (m_logical_loc_mgr) + if (auto client_data_hooks = m_context.get_client_data_hooks ()) + if (auto logical_loc = client_data_hooks->get_current_logical_location ()) + if (logical_loc != m_last_logical_location) + { + enum logical_location_kind kind + = m_logical_loc_mgr->get_kind (logical_loc);; + if (const char *label = get_label_for_logical_location_kind (kind)) + if (const char *name_with_scope + = m_logical_loc_mgr->get_name_with_scope (logical_loc)) + add_labelled_value (xp, "logical-location", + label, name_with_scope, true); + m_last_logical_location = logical_loc; + } + + /* Show any physical location. */ + const expanded_location s + = diagnostic_expand_location (&diagnostic); + if (s != m_last_expanded_location + || alert) + { + if (s.file + && (s.file != m_last_expanded_location.file + || alert)) + add_labelled_value (xp, "file", "File", s.file, false); + if (s.line) + { + add_labelled_value (xp, "line", "Line", std::to_string (s.line), false); + diagnostic_column_policy column_policy (m_context); + int converted_column = column_policy.converted_column (s); + if (converted_column >= 0) + add_labelled_value (xp, "column", "Column", + std::to_string (converted_column), + false); + } + if (s.file) + m_last_expanded_location = s; } /* Source (and fix-it hints). */ { - xml::printer xp (*diag_element); - m_context.m_last_location = UNKNOWN_LOCATION; + // TODO: m_context.m_last_location should be moved into the sink + location_t saved = m_context.m_last_location; + m_context.m_last_location = m_last_location; m_context.maybe_show_locus_as_html (*diagnostic.richloc, m_context.m_source_printing, diagnostic.kind, xp, nullptr, nullptr); + m_context.m_last_location = saved; + m_last_location = m_context.m_last_location; } + gcc_assert (xp.get_num_open_tags () == depth_within_alert_div); + /* Execution path. */ if (auto path = diagnostic.richloc->get_path ()) { - xml::printer xp (*diag_element); + xp.push_tag ("div"); + xp.set_attr ("id", "execution-path"); + + xp.push_tag ("label", true); + const int num_events = path->num_events (); + pretty_printer pp; + pp_printf_n (&pp, num_events, + "Execution path with %i event", + "Execution path with %i events", + num_events); + xp.add_text_from_pp (pp); + xp.pop_tag ("label"); + std::string event_id_prefix (diag_id + "-event-"); html_path_label_writer event_label_writer (xp, *this, event_id_prefix); diagnostic_source_print_policy dspp (m_context); print_path_as_html (xp, *path, m_context, &event_label_writer, dspp); + + xp.pop_tag ("div"); } + gcc_assert (xp.get_num_open_tags () == depth_within_alert_div); + if (auto patch_element = make_element_for_patch (diagnostic)) - diag_element->add_child (std::move (patch_element)); + { + xp.push_tag ("div"); + xp.set_attr ("id", "suggested-fix"); + xp.push_tag ("label", true); + xp.add_text ("Suggested fix"); + xp.pop_tag ("label"); + xp.append (std::move (patch_element)); + xp.pop_tag ("div"); + } return diag_element; } @@ -664,7 +1064,7 @@ html_builder::make_metadata_element (label_text label, } xp.add_text (label.get ()); if (url.get ()) - xp.pop_tag (); + xp.pop_tag ("a"); } xp.add_text ("]"); return item; @@ -739,7 +1139,7 @@ html_builder::flush_to_file (FILE *outf) m_ui_focus_ids.print (&pp, true); pp_string (&pp, ";\n"); xp.add_raw (pp_formatted_text (&pp)); - xp.pop_tag (); // script + xp.pop_tag ("script"); } auto top = m_document.get (); top->dump (outf); @@ -765,6 +1165,12 @@ public: diagnostic_output_format::dump (out, indent); } + void + set_main_input_filename (const char *name) final override + { + m_builder.set_main_input_filename (name); + } + std::unique_ptr<diagnostic_per_format_buffer> make_per_format_buffer () final override { @@ -924,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. */ @@ -940,6 +1393,7 @@ public: line_table, html_gen_opts); sink->update_printer (); + sink->set_main_input_filename ("(main input filename)"); m_format = sink.get (); // borrowed set_output_format (std::move (sink)); @@ -988,22 +1442,21 @@ 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" " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n" "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" " <head>\n" - " <title>Title goes here</title>\n" + " <title>(main input filename)</title>\n" " </head>\n" " <body>\n" " <div class=\"gcc-diagnostic-list\">\n" - " <div class=\"gcc-diagnostic\" id=\"gcc-diag-0\">\n" - " <span class=\"gcc-message\" id=\"gcc-diag-0-message\">this is a test: `<span class=\"gcc-quoted-text\">foo</span>'</span>\n" + " <div class=\"alert alert-danger\" id=\"gcc-diag-0\">\n" + " <span class=\"pficon pficon-error-circle-o\"> </span>\n" + " <div class=\"gcc-message\" id=\"gcc-diag-0-message\"><strong>error: </strong> this is a test: `<span class=\"gcc-quoted-text\">foo</span>'</div>\n" " </div>\n" " </div>\n" " </body>\n" @@ -1020,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\">" "[" @@ -1041,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\">" "[" @@ -1063,6 +1512,7 @@ void diagnostic_format_html_cc_tests () { auto_fix_quotes fix_quotes; + test_token_printer (); test_simple_log (); test_metadata (); } |