#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 "selftest.h"
#include "selftest-diagnostic.h"
#include "pretty-print-format-impl.h"
+#include "pretty-print-urlifier.h"
+#include "edit-context.h"
#include "intl.h"
namespace xml {
friend class diagnostic_html_format_buffer;
html_builder (diagnostic_context &context,
- pretty_printer &pp,
- const line_maps *line_maps);
+ pretty_printer &pp,
+ const line_maps *line_maps);
void on_report_diagnostic (const diagnostic_info &diagnostic,
diagnostic_t orig_diag_kind,
m_printer = &pp;
}
+ std::unique_ptr<xml::element>
+ make_element_for_metadata (const diagnostic_metadata &metadata);
+
+ std::unique_ptr<xml::element>
+ make_element_for_source (const diagnostic_info &diagnostic);
+
+ std::unique_ptr<xml::element>
+ make_element_for_path (const diagnostic_path &path);
+
+ std::unique_ptr<xml::element>
+ make_element_for_patch (const diagnostic_info &diagnostic);
+
private:
std::unique_ptr<xml::element>
make_element_for_diagnostic (const diagnostic_info &diagnostic,
diagnostic_t orig_diag_kind);
+ std::unique_ptr<xml::element>
+ make_metadata_element (label_text label,
+ label_text url);
+
diagnostic_context &m_context;
pretty_printer *m_printer;
const line_maps *m_line_maps;
if (diagnostic.metadata)
{
- int cwe = diagnostic.metadata->get_cwe ();
- if (cwe)
- {
- diag_element->add_text (label_text::borrow (" "));
- auto cwe_span = make_span (label_text::borrow ("gcc-cwe-metadata"));
- cwe_span->add_text (label_text::borrow ("["));
- {
- auto anchor = std::make_unique<xml::element> ("a", true);
- anchor->set_attr ("href", label_text::take (get_cwe_url (cwe)));
- pretty_printer pp;
- pp_printf (&pp, "CWE-%i", cwe);
- anchor->add_text
- (label_text::take (xstrdup (pp_formatted_text (&pp))));
- cwe_span->add_child (std::move (anchor));
- }
- cwe_span->add_text (label_text::borrow ("]"));
- diag_element->add_child (std::move (cwe_span));
- }
+ diag_element->add_text (label_text::borrow (" "));
+ diag_element->add_child
+ (make_element_for_metadata (*diagnostic.metadata));
}
- // TODO: show any rules
-
label_text option_text = label_text::take
(m_context.make_option_name (diagnostic.option_id,
orig_diag_kind, diagnostic.kind));
diag_element->add_child (std::move (option_span));
}
+ /* Source (and fix-it hints). */
+ if (auto source_element = make_element_for_source (diagnostic))
+ diag_element->add_child (std::move (source_element));
+
+ /* Execution path. */
+ if (auto path = diagnostic.richloc->get_path ())
+ if (auto path_element = make_element_for_path (*path))
+ diag_element->add_child (std::move (path_element));
+
+ if (auto patch_element = make_element_for_patch (diagnostic))
+ diag_element->add_child (std::move (patch_element));
+
+ return diag_element;
+}
+
+std::unique_ptr<xml::element>
+html_builder::make_element_for_source (const diagnostic_info &diagnostic)
+{
+ // TODO: ideally we'd like to capture elements within the following:
+ m_context.m_last_location = UNKNOWN_LOCATION;
+ pp_clear_output_area (m_printer);
+ diagnostic_show_locus (&m_context,
+ m_context.m_source_printing,
+ diagnostic.richloc, diagnostic.kind,
+ m_printer);
+ auto text = label_text::take (xstrdup (pp_formatted_text (m_printer)));
+ pp_clear_output_area (m_printer);
+
+ if (strlen (text.get ()) == 0)
+ return nullptr;
+
+ auto pre = std::make_unique<xml::element> ("pre", true);
+ pre->set_attr ("class", label_text::borrow ("gcc-annotated-source"));
+ pre->add_text (std::move (text));
+ return pre;
+}
+
+std::unique_ptr<xml::element>
+html_builder::make_element_for_path (const diagnostic_path &path)
+{
+ m_context.m_last_location = UNKNOWN_LOCATION;
+ diagnostic_text_output_format text_format (m_context);
+ pp_show_color (text_format.get_printer ()) = false;
+ pp_buffer (text_format.get_printer ())->m_flush_p = false;
+ // TODO: ideally we'd like to capture elements within the following:
+ text_format.print_path (path);
+ auto text = label_text::take
+ (xstrdup (pp_formatted_text (text_format.get_printer ())));
+
+ if (strlen (text.get ()) == 0)
+ return nullptr;
+
+ auto pre = std::make_unique<xml::element> ("pre", true);
+ pre->set_attr ("class", label_text::borrow ("gcc-execution-path"));
+ pre->add_text (std::move (text));
+ return pre;
+}
+
+std::unique_ptr<xml::element>
+html_builder::make_element_for_patch (const diagnostic_info &diagnostic)
+{
+ edit_context ec (m_context.get_file_cache ());
+ ec.add_fixits (diagnostic.richloc);
+ if (char *diff = ec.generate_diff (true))
+ if (strlen (diff) > 0)
+ {
+ auto element = std::make_unique<xml::element> ("pre", true);
+ element->set_attr ("class", label_text::borrow ("gcc-generated-patch"));
+ element->add_text (label_text::take (diff));
+ return element;
+ }
+ return nullptr;
+}
+
+std::unique_ptr<xml::element>
+html_builder::make_metadata_element (label_text label,
+ label_text url)
+{
+ auto item = make_span (label_text::borrow ("gcc-metadata-item"));
+ item->add_text (label_text::borrow ("["));
{
- auto pre = std::make_unique<xml::element> ("pre", true);
- pre->set_attr ("class", label_text::borrow ("gcc-annotated-source"));
- // TODO: ideally we'd like to capture elements within the following:
- diagnostic_show_locus (&m_context, m_context.m_source_printing,
- diagnostic.richloc, diagnostic.kind,
- m_printer);
- pre->add_text
- (label_text::take (xstrdup (pp_formatted_text (m_printer))));
- pp_clear_output_area (m_printer);
- diag_element->add_child (std::move (pre));
+ auto anchor = std::make_unique<xml::element> ("a", true);
+ anchor->set_attr ("href", std::move (url));
+ anchor->add_child (std::make_unique<xml::text> (std::move (label)));
+ item->add_child (std::move (anchor));
}
+ item->add_text (label_text::borrow ("]"));
+ return item;
+}
- return diag_element;
+std::unique_ptr<xml::element>
+html_builder::make_element_for_metadata (const diagnostic_metadata &metadata)
+{
+ auto span_metadata = make_span (label_text::borrow ("gcc-metadata"));
+
+ int cwe = metadata.get_cwe ();
+ if (cwe)
+ {
+ pretty_printer pp;
+ pp_printf (&pp, "CWE-%i", cwe);
+ label_text label = label_text::take (xstrdup (pp_formatted_text (&pp)));
+ label_text url = label_text::take (get_cwe_url (cwe));
+ span_metadata->add_child
+ (make_metadata_element (std::move (label), std::move (url)));
+ }
+
+ for (unsigned idx = 0; idx < metadata.get_num_rules (); ++idx)
+ {
+ auto &rule = metadata.get_rule (idx);
+ label_text label = label_text::take (rule.make_description ());
+ label_text url = label_text::take (rule.make_url ());
+ span_metadata->add_child
+ (make_metadata_element (std::move (label), std::move (url)));
+ }
+
+ return span_metadata;
}
/* Implementation of diagnostic_context::m_diagrams.m_emission_cb
return m_builder.get_document ();
}
+ html_builder &get_builder () { return m_builder; }
+
protected:
html_output_format (diagnostic_context &context,
const line_maps *line_maps)
return m_format->get_document ();
}
+ html_builder &get_builder () const
+ {
+ return m_format->get_builder ();
+ }
+
private:
class html_buffered_output_format : public html_output_format
{
test_html_diagnostic_context dc;
rich_location richloc (line_table, UNKNOWN_LOCATION);
- dc.report (DK_ERROR, richloc, nullptr, 0, "this is a test: %i", 42);
+ dc.report (DK_ERROR, richloc, nullptr, 0, "this is a test: %qs", "foo");
const xml::document &doc = dc.get_document ();
" <body>\n"
" <div class=\"gcc-diagnostic-list\">\n"
" <div class=\"gcc-diagnostic\">\n"
- " <span class=\"gcc-message\">this is a test: 42</span>\n"
- " <pre class=\"gcc-annotated-source\"></pre>\n"
+ " <span class=\"gcc-message\">this is a test: `<span class=\"gcc-quoted-text\">foo</span>'</span>\n"
" </div>\n"
" </div>\n"
" </body>\n"
"</html>"));
}
+static void
+test_metadata ()
+{
+ test_html_diagnostic_context dc;
+ html_builder &b = dc.get_builder ();
+
+ {
+ 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),
+ "\n"
+ "<span class=\"gcc-metadata\">"
+ "<span class=\"gcc-metadata-item\">"
+ "["
+ "<a href=\"https://cwe.mitre.org/data/definitions/415.html\">"
+ "CWE-415"
+ "</a>"
+ "]"
+ "</span>"
+ "</span>");
+ }
+
+ {
+ diagnostic_metadata metadata;
+ diagnostic_metadata::precanned_rule rule ("MISC-42",
+ "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),
+ "\n"
+ "<span class=\"gcc-metadata\">"
+ "<span class=\"gcc-metadata-item\">"
+ "["
+ "<a href=\"http://example.com\">"
+ "MISC-42"
+ "</a>"
+ "]"
+ "</span>"
+ "</span>");
+ }
+}
+
/* Run all of the selftests within this file. */
void
diagnostic_format_html_cc_tests ()
{
+ auto_fix_quotes fix_quotes;
test_simple_log ();
+ test_metadata ();
}
} // namespace selftest
--- /dev/null
+# Verify that metadata works in HTML output.
+
+from htmltest import *
+
+import pytest
+
+@pytest.fixture(scope='function', autouse=True)
+def html_tree():
+ return html_tree_from_env()
+
+XHTML = 'http://www.w3.org/1999/xhtml'
+ns = {'xhtml': XHTML}
+
+def make_tag(local_name):
+ return f'{{{XHTML}}}' + local_name
+
+def test_metadata(html_tree):
+ root = html_tree.getroot ()
+ assert root.tag == make_tag('html')
+
+ body = root.find('xhtml:body', ns)
+ assert body is not None
+
+ diag_list = body.find('xhtml:div', ns)
+ assert diag_list is not None
+ assert diag_list.attrib['class'] == 'gcc-diagnostic-list'
+
+ diag = diag_list.find('xhtml:div', ns)
+ assert diag is not None
+ assert diag.attrib['class'] == 'gcc-diagnostic'
+
+ spans = diag.findall('xhtml:span', ns)
+ metadata = spans[1]
+ assert metadata.attrib['class'] == 'gcc-metadata'
+ assert metadata[0].tag == make_tag('span')
+ assert metadata[0].attrib['class'] == 'gcc-metadata-item'
+ assert metadata[0].text == '['
+ assert metadata[0][0].tag == make_tag('a')
+ assert metadata[0][0].attrib['href'] == 'https://cwe.mitre.org/data/definitions/242.html'
+ assert metadata[0][0].text == 'CWE-242'
+ assert metadata[0][0].tail == ']'
+
+ assert metadata[1].tag == make_tag('span')
+ assert metadata[1].attrib['class'] == 'gcc-metadata-item'
+ assert metadata[1].text == '['
+ assert metadata[1][0].tag == make_tag('a')
+ assert metadata[1][0].attrib['href'] == 'https://example.com/'
+ assert metadata[1][0].text == 'STR34-C'
+ assert metadata[1][0].tail == ']'
+
+ src = diag.find('xhtml:pre', ns)
+ assert src.attrib['class'] == 'gcc-annotated-source'
+ assert src.text == (
+ ' gets (buf);\n'
+ ' ^~~~~~~~~~\n')
+
+# For reference, here's the generated HTML:
+"""
+ <body>
+ <div class="gcc-diagnostic-list">
+ <div class="gcc-diagnostic">
+ <span class="gcc-message">never use '<span class="gcc-quoted-text">gets</span>'</span>
+ <span class="gcc-metadata"><span class="gcc-metadata-item">[<a href="https://cwe.mitre.org/data/definitions/242.html">CWE-242</a>]</span><span class="gcc-metadata-item">[<a href="https://example.com/">STR34-C</a>]</span></span>
+ ...etc...
+ </div>
+ </div>
+ </body>
+"""