...
+ 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 (" ");
+ }
+
+ // 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));
@@ -603,7 +904,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 ("[");
{
@@ -618,35 +919,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;
}
@@ -1032,8 +1408,9 @@ test_simple_log ()
" \n"
" \n"
"
\n"
- "
\n"
- "
this is a test: `foo'\n"
+ "
\n"
+ "
\n"
+ "
error: this is a test: `foo'
\n"
"
\n"
"
\n"
" \n"
diff --git a/gcc/testsuite/gcc.dg/format/diagnostic-ranges-html.py b/gcc/testsuite/gcc.dg/format/diagnostic-ranges-html.py
index 1d798939e729..b0b59d951ca8 100644
--- a/gcc/testsuite/gcc.dg/format/diagnostic-ranges-html.py
+++ b/gcc/testsuite/gcc.dg/format/diagnostic-ranges-html.py
@@ -19,17 +19,20 @@ def test_message(html_tree):
diag = get_diag_by_index(html_tree, 0)
msg = get_message_within_diag(diag)
- assert_tag(msg[0], 'span')
- assert_class(msg[0], 'gcc-quoted-text')
- assert_highlighted_text(msg[0][0], 'highlight-a', '%i')
-
+ assert_tag(msg[0], 'strong')
+ assert msg[0].text == 'warning: '
+
assert_tag(msg[1], 'span')
assert_class(msg[1], 'gcc-quoted-text')
- assert_highlighted_text(msg[1][0], 'highlight-a', 'int')
+ assert_highlighted_text(msg[1][0], 'highlight-a', '%i')
assert_tag(msg[2], 'span')
assert_class(msg[2], 'gcc-quoted-text')
- assert_highlighted_text(msg[2][0], 'highlight-b', 'const char *')
+ assert_highlighted_text(msg[2][0], 'highlight-a', 'int')
+
+ assert_tag(msg[3], 'span')
+ assert_class(msg[3], 'gcc-quoted-text')
+ assert_highlighted_text(msg[3][0], 'highlight-b', 'const char *')
def test_annotations(html_tree):
"""
diff --git a/gcc/testsuite/gcc.dg/html-output/missing-semicolon.py b/gcc/testsuite/gcc.dg/html-output/missing-semicolon.py
index 880fcc0231bc..3adaa52ee64d 100644
--- a/gcc/testsuite/gcc.dg/html-output/missing-semicolon.py
+++ b/gcc/testsuite/gcc.dg/html-output/missing-semicolon.py
@@ -37,22 +37,68 @@ def test_basics(html_tree):
diag = diag_list.find('xhtml:div', ns)
assert diag is not None
- assert diag.attrib['class'] == 'gcc-diagnostic'
+ assert diag.attrib['class'] == 'alert alert-danger'
+ assert diag.attrib['id'] == 'gcc-diag-0'
- message = diag.find('xhtml:span', ns)
+ icon = diag.find('xhtml:span', ns)
+ assert icon.attrib['class'] == 'pficon pficon-error-circle-o'
+
+ # The message line:
+ message = diag.find("./xhtml:div[@class='gcc-message']", ns)
assert message is not None
- assert message.attrib['class'] == 'gcc-message'
- assert message.text == "expected '"
- assert message[0].tag == make_tag('span')
- assert message[0].attrib['class'] == 'gcc-quoted-text'
- assert message[0].text == ';'
- assert message[0].tail == "' before '"
+ #
error: expected ';' before '}' token
+ assert message[0].tag == make_tag('strong')
+ assert message[0].text == 'error: '
+ assert message[0].tail == " expected '"
assert message[1].tag == make_tag('span')
assert message[1].attrib['class'] == 'gcc-quoted-text'
- assert message[1].text == '}'
- assert message[1].tail == "' token"
+ assert message[1].text == ';'
+ assert message[1].tail == "' before '"
+ assert message[2].tag == make_tag('span')
+ assert message[2].attrib['class'] == 'gcc-quoted-text'
+ assert message[2].text == '}'
+ assert message[2].tail == "' token"
- pre = diag.find('xhtml:pre', ns)
+ # Logical location
+ logical_loc = diag.find("./xhtml:div[@id='logical-location']", ns)
+ assert logical_loc is not None
+ assert len(logical_loc) == 2
+ assert logical_loc[0].tag == make_tag('span')
+ assert logical_loc[0].text == 'Function '
+ assert logical_loc[1].tag == make_tag('span')
+ assert logical_loc[1].text == 'missing_semicolon'
+ assert logical_loc[1].attrib['class'] == 'gcc-quoted-text'
+
+ # Physical location
+ file_ = diag.find("./xhtml:div[@id='file']", ns)
+ assert file_ is not None
+ assert len(file_) == 2
+ assert file_[0].tag == make_tag('span')
+ assert file_[0].text == 'File '
+ assert file_[1].tag == make_tag('span')
+ assert file_[1].text.endswith('gcc/testsuite/gcc.dg/html-output/missing-semicolon.c')
+
+ line = diag.find("./xhtml:div[@id='line']", ns)
+ assert line is not None
+ assert len(line) == 2
+ assert line[0].tag == make_tag('span')
+ assert line[0].text == 'Line '
+ assert line[1].tag == make_tag('span')
+ assert line[1].text == '8'
+
+ column = diag.find("./xhtml:div[@id='column']", ns)
+ assert column is not None
+ assert len(column) == 2
+ assert column[0].tag == make_tag('span')
+ assert column[0].text == 'Column '
+ assert column[1].tag == make_tag('span')
+ assert column[1].text == '12'
+
+ # Suggested fix
+ fix = diag.find("./xhtml:div[@id='suggested-fix']", ns)
+ label = fix.find('xhtml:label', ns)
+ assert label.text == "Suggested fix"
+ pre = fix.find('xhtml:pre', ns)
assert pre is not None
assert pre.attrib['class'] == 'gcc-generated-patch'
assert pre.text.startswith('--- ')
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-metadata-html.py b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-metadata-html.py
index b4c75b230ee2..67fb241d179c 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-metadata-html.py
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-metadata-html.py
@@ -21,10 +21,24 @@ def test_metadata(html_tree):
diag = diag_list.find('xhtml:div', ns)
assert diag is not None
- assert diag.attrib['class'] == 'gcc-diagnostic'
+ assert diag.attrib['class'] == 'alert alert-warning'
- spans = diag.findall('xhtml:span', ns)
- metadata = spans[1]
+ icon = diag.find('xhtml:span', ns)
+ assert icon.attrib['class'] == 'pficon pficon-warning-triangle-o'
+
+ message = diag.find("./xhtml:div[@class='gcc-message']", ns)
+ assert message.attrib['id'] == 'gcc-diag-0-message'
+
+ assert message[0].tag == make_tag('strong')
+ assert message[0].text == 'warning: '
+ assert message[0].tail == " never use '"
+
+ assert message[1].tag == make_tag('span')
+ assert message[1].attrib['class'] == 'gcc-quoted-text'
+ assert message[1].text == 'gets'
+ assert message[1].tail == "' "
+
+ metadata = message[2]
assert metadata.attrib['class'] == 'gcc-metadata'
assert metadata[0].tag == make_tag('span')
assert metadata[0].attrib['class'] == 'gcc-metadata-item'
@@ -57,21 +71,3 @@ def test_metadata(html_tree):
annotation_tr = rows[1]
assert_annotation_line(annotation_tr,
' ^~~~~~~~~~')
-
-# For reference, here's the generated HTML:
-"""
-
-
-
-
never use 'gets'
-
[CWE-242][STR34-C]
-
-| 10 | gets (buf); |
- | ^~~~~~~~~~ |
-
-
-
-
-
-
-"""
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-2.py b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-2.py
index 59bee247103f..f0fed45626ef 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-2.py
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-2.py
@@ -21,9 +21,16 @@ def test_paths(html_tree):
diag = diag_list.find('xhtml:div', ns)
assert diag is not None
- assert diag.attrib['class'] == 'gcc-diagnostic'
+ assert diag.attrib['class'] == 'alert alert-danger'
+ assert diag.attrib['id'] == 'gcc-diag-0'
- event_ranges = diag.find('xhtml:div', ns)
+ exec_path = diag.find("./xhtml:div[@id='execution-path']", ns)
+ assert exec_path is not None
+
+ label = exec_path.find('xhtml:label', ns)
+ assert label.text == 'Execution path with 3 events'
+
+ event_ranges = exec_path.find('xhtml:div', ns)
assert_class(event_ranges, 'event-ranges')
frame_margin = event_ranges.find('xhtml:table', ns)
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-4.py b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-4.py
index e738729a3472..d2bc67c52a29 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-4.py
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-paths-4.py
@@ -25,7 +25,13 @@ def test_paths(html_tree):
assert_annotation_line(annotation_tr,
' ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
- event_ranges = diag.find('xhtml:div', ns)
+ exec_path = diag.find("./xhtml:div[@id='execution-path']", ns)
+ assert exec_path is not None
+
+ label = exec_path.find('xhtml:label', ns)
+ assert label.text == 'Execution path with 9 events'
+
+ event_ranges = exec_path.find('xhtml:div', ns)
assert_class(event_ranges, 'event-ranges')
test_frame_margin = event_ranges.find('xhtml:table', ns)
@@ -41,150 +47,3 @@ def test_paths(html_tree):
test_frame = tds[1]
assert_frame(test_frame, 'test')
assert_event_range_with_margin(test_frame[1])
-
-# For reference, generated HTML looks like this:
-"""
-
- |
-
- test
- |
- test: events 1-2
-
-
-| 27 | { |
- | ^ |
- | | |
- | (1) entering 'test' |
-| 28 | register_handler (); |
- | ~~~~~~~~~~~~~~~~~~~ |
- | | |
- | (2) calling 'register_handler' |
-
-
- |
-
-
-
- |
-
- register_handler
- |
- register_handler: events 3-4
-
-
-| 22 | { |
- | ^ |
- | | |
- | (3) entering 'register_handler' |
-| 23 | signal(SIGINT, int_handler); |
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- | | |
- | (4) registering 'int_handler' as signal handler |
-
-
- |
- |
- |
-
-
-
- |
- event 5
- (5): later on, when the signal is delivered to the process
- |
-
-
-
- |
-
- int_handler
- |
- int_handler: events 6-7
-
-
-| 17 | { |
- | ^ |
- | | |
- | (6) entering 'int_handler' |
-| 18 | custom_logger("got signal"); |
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- | | |
- | (7) calling 'custom_logger' |
-
-
- |
-
-
-
- |
-
- custom_logger
- |
- custom_logger: events 8-9
-
-
-| 12 | { |
- | ^ |
- | | |
- | (8) entering 'custom_logger' |
-| 13 | fprintf(stderr, "LOG: %s", msg); /* { dg-warning "call to 'fprintf' from within signal handler" } */ |
- | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
- | | |
- | (9) calling 'fprintf' |
-
-
- |
- |
- |
-
-
- """
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus.py b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus.py
index d963b29830b5..aca1b6cdaccd 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus.py
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus.py
@@ -46,7 +46,8 @@ def test_very_wide_line(html_tree):
def test_fixit_insert(html_tree):
diag = get_diag_by_index(html_tree, 3)
msg = get_message_within_diag(diag)
- assert msg.text == 'example of insertion hints'
+ assert msg[0].text == 'warning: '
+ assert msg[0].tail == ' example of insertion hints'
src = get_locus_within_diag(diag)
@@ -62,7 +63,8 @@ def test_fixit_insert(html_tree):
def test_fixit_remove(html_tree):
diag = get_diag_by_index(html_tree, 4)
msg = get_message_within_diag(diag)
- assert msg.text == 'example of a removal hint'
+ assert msg[0].text == 'warning: '
+ assert msg[0].tail == ' example of a removal hint'
src = get_locus_within_diag(diag)
@@ -78,7 +80,8 @@ def test_fixit_remove(html_tree):
def test_fixit_replace(html_tree):
diag = get_diag_by_index(html_tree, 5)
msg = get_message_within_diag(diag)
- assert msg.text == 'example of a replacement hint'
+ assert msg[0].text == 'warning: '
+ assert msg[0].tail == ' example of a replacement hint'
src = get_locus_within_diag(diag)
@@ -94,7 +97,8 @@ def test_fixit_replace(html_tree):
def test_fixit_insert_newline(html_tree):
diag = get_diag_by_index(html_tree, 6)
msg = get_message_within_diag(diag)
- assert msg.text == 'example of newline insertion hint'
+ assert msg[0].text == 'warning: '
+ assert msg[0].tail == ' example of newline insertion hint'
src = get_locus_within_diag(diag)
diff --git a/gcc/testsuite/lib/htmltest.py b/gcc/testsuite/lib/htmltest.py
index 8e42a8c2a17e..49ed4b035820 100644
--- a/gcc/testsuite/lib/htmltest.py
+++ b/gcc/testsuite/lib/htmltest.py
@@ -83,14 +83,11 @@ def get_diag_by_index(html_tree, index):
assert diag_list is not None
assert_class(diag_list, 'gcc-diagnostic-list')
- diags = diag_list.findall('xhtml:div', ns)
- diag = diags[index]
- assert_class(diag, 'gcc-diagnostic')
+ diag = diag_list.find(f"xhtml:div[@id='gcc-diag-{index}']", ns)
return diag
def get_message_within_diag(diag_element):
- msg = diag_element.find('xhtml:span', ns)
- assert_class(msg, 'gcc-message')
+ msg = diag_element.find("xhtml:div[@class='gcc-message']", ns)
return msg
def get_locus_within_diag(diag_element):
diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h
index 75cc1ad2c275..83ebbde474df 100644
--- a/libcpp/include/line-map.h
+++ b/libcpp/include/line-map.h
@@ -1280,7 +1280,7 @@ linemap_location_before_p (const line_maps *set,
return linemap_compare_locations (set, loc_a, loc_b) >= 0;
}
-typedef struct
+struct expanded_location
{
/* The name of the source file involved. */
const char *file;
@@ -1294,7 +1294,18 @@ typedef struct
/* In a system header?. */
bool sysp;
-} expanded_location;
+};
+
+extern bool
+operator== (const expanded_location &a,
+ const expanded_location &b);
+inline bool
+operator!= (const expanded_location &a,
+ const expanded_location &b)
+{
+ return !(a == b);
+}
+
/* This is enum is used by the function linemap_resolve_location
below. The meaning of the values is explained in the comment of
diff --git a/libcpp/line-map.cc b/libcpp/line-map.cc
index cf6557117c81..284af5781dcf 100644
--- a/libcpp/line-map.cc
+++ b/libcpp/line-map.cc
@@ -1949,6 +1949,28 @@ linemap_expand_location (const line_maps *set,
return xloc;
}
+bool
+operator== (const expanded_location &a,
+ const expanded_location &b)
+{
+ /* "file" can be null; for them to be equal they must both
+ have either null or nonnull values, and if non-null
+ they must compare as equal. */
+ if ((a.file == nullptr) != (b.file == nullptr))
+ return false;
+ if (a.file && strcmp (a.file, b.file))
+ return false;
+
+ if (a.line != b.line)
+ return false;
+ if (a.column != b.column)
+ return false;
+ if (a.data != b.data)
+ return false;
+ if (a.sysp != b.sysp)
+ return false;
+ return true;
+}
/* Dump line map at index IX in line table SET to STREAM. If STREAM
is NULL, use stderr. IS_MACRO is true if the caller wants to