aboutsummaryrefslogtreecommitdiff
path: root/gcc/diagnostics
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/diagnostics')
-rw-r--r--gcc/diagnostics/buffering.cc5
-rw-r--r--gcc/diagnostics/buffering.h10
-rw-r--r--gcc/diagnostics/column-options.h44
-rw-r--r--gcc/diagnostics/context.cc276
-rw-r--r--gcc/diagnostics/context.h190
-rw-r--r--gcc/diagnostics/counters.h51
-rw-r--r--gcc/diagnostics/dumping.cc102
-rw-r--r--gcc/diagnostics/dumping.h50
-rw-r--r--gcc/diagnostics/file-cache.cc49
-rw-r--r--gcc/diagnostics/html-sink.cc58
-rw-r--r--gcc/diagnostics/html-sink.h2
-rw-r--r--gcc/diagnostics/kinds.h1
-rw-r--r--gcc/diagnostics/lazy-paths.cc6
-rw-r--r--gcc/diagnostics/logging.cc72
-rw-r--r--gcc/diagnostics/logging.h230
-rw-r--r--gcc/diagnostics/metadata.h2
-rw-r--r--gcc/diagnostics/option-id-manager.h56
-rw-r--r--gcc/diagnostics/output-file.h2
-rw-r--r--gcc/diagnostics/output-spec.cc67
-rw-r--r--gcc/diagnostics/sarif-sink.cc89
-rw-r--r--gcc/diagnostics/sarif-sink.h4
-rw-r--r--gcc/diagnostics/sink.h5
-rw-r--r--gcc/diagnostics/source-printing-options.h76
-rw-r--r--gcc/diagnostics/source-printing.cc8
-rw-r--r--gcc/diagnostics/text-sink.cc32
-rw-r--r--gcc/diagnostics/text-sink.h8
26 files changed, 1185 insertions, 310 deletions
diff --git a/gcc/diagnostics/buffering.cc b/gcc/diagnostics/buffering.cc
index 29f039f..a7747b5 100644
--- a/gcc/diagnostics/buffering.cc
+++ b/gcc/diagnostics/buffering.cc
@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic.h"
#include "diagnostics/buffering.h"
#include "diagnostics/sink.h"
+#include "diagnostics/dumping.h"
namespace diagnostics {
@@ -122,12 +123,12 @@ void
buffer::dump (FILE *out, int indent) const
{
m_diagnostic_counters.dump (out, indent + 2);
- fprintf (out, "%*sm_per_sink_buffers:\n", indent, "");
+ dumping::emit_heading (out, indent, "m_per_sink_buffers");
if (m_per_sink_buffers)
for (auto per_sink_buffer_ : *m_per_sink_buffers)
per_sink_buffer_->dump (out, indent + 2);
else
- fprintf (out, "%*s(none)\n", indent + 2, "");
+ dumping::emit_none (out, indent + 2);
}
bool
diff --git a/gcc/diagnostics/buffering.h b/gcc/diagnostics/buffering.h
index c3ac070..9b86fee 100644
--- a/gcc/diagnostics/buffering.h
+++ b/gcc/diagnostics/buffering.h
@@ -36,7 +36,7 @@ class sink;
A diagnostics::buffer can be:
* flushed to the diagnostics::context, which issues
- the diagnostics within the buffer to the output format
+ the diagnostics within the buffer to the output sinks
and checks for limits such as -fmax-errors=, or
* moved to another diagnostics::buffer, which moves the diagnostics
@@ -45,13 +45,13 @@ class sink;
source buffer, or
* cleared, which discards any diagnostics within the buffer
- without issuing them to the output format.
+ without issuing them to the output sinks.
- Since a buffer needs to contain output-format-specific data,
- it's not possible to change the output format of the
+ Since a buffer needs to contain sink-specific data,
+ it's not possible to change the output sink(s) of the
diagnostics::context once any buffers are non-empty.
- To simplify implementing output formats, it's not possible
+ To simplify implementing output sinks, it's not possible
to change buffering on a diagnostics::context whilst within a
diagnostic group. */
diff --git a/gcc/diagnostics/column-options.h b/gcc/diagnostics/column-options.h
new file mode 100644
index 0000000..86296e9
--- /dev/null
+++ b/gcc/diagnostics/column-options.h
@@ -0,0 +1,44 @@
+/* Options relating to the meaning of column numbers.
+ Copyright (C) 2000-2025 Free Software Foundation, Inc.
+
+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
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_DIAGNOSTICS_COLUMN_OPTIONS_H
+#define GCC_DIAGNOSTICS_COLUMN_OPTIONS_H
+
+namespace diagnostics {
+
+/* A bundle of options relating to the meaning of column numbers. */
+
+struct column_options
+{
+ int convert_column (file_cache &fc,
+ expanded_location s) const;
+
+ /* What units to use when outputting the column number. */
+ enum diagnostics_column_unit m_column_unit;
+
+ /* The origin for the column number (1-based or 0-based typically). */
+ int m_column_origin;
+
+ /* The size of the tabstop for tab expansion. */
+ int m_tabstop;
+};
+
+} // namespace diagnostics
+
+#endif /* ! GCC_DIAGNOSTICS_COLUMN_OPTIONS_H */
diff --git a/gcc/diagnostics/context.cc b/gcc/diagnostics/context.cc
index 85f7d2a..0f8670b 100644
--- a/gcc/diagnostics/context.cc
+++ b/gcc/diagnostics/context.cc
@@ -50,6 +50,8 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostics/logical-locations.h"
#include "diagnostics/buffering.h"
#include "diagnostics/file-cache.h"
+#include "diagnostics/dumping.h"
+#include "diagnostics/logging.h"
#ifdef HAVE_TERMIOS_H
# include <termios.h>
@@ -170,18 +172,24 @@ context::initialize (int n_opts)
m_text_callbacks.m_html_start_span
= default_start_span_fn<to_html>;
m_text_callbacks.m_end_diagnostic = default_text_finalizer;
- m_option_mgr = nullptr;
+ m_option_id_mgr = nullptr;
m_urlifier_stack = new auto_vec<urlifier_stack_node> ();
m_last_location = UNKNOWN_LOCATION;
m_client_aux_data = nullptr;
m_lock = 0;
m_inhibit_notes_p = false;
+
m_source_printing.colorize_source_p = false;
m_source_printing.show_labels_p = false;
m_source_printing.show_line_numbers_p = false;
m_source_printing.min_margin_width = 0;
m_source_printing.show_ruler_p = false;
m_source_printing.show_event_links_p = false;
+
+ m_column_options.m_column_unit = DIAGNOSTICS_COLUMN_UNIT_DISPLAY;
+ m_column_options.m_column_origin = 1;
+ m_column_options.m_tabstop = 8;
+
m_report_bug = false;
m_extra_output_kind = EXTRA_DIAGNOSTIC_OUTPUT_none;
if (const char *var = getenv ("GCC_EXTRA_DIAGNOSTIC_OUTPUT"))
@@ -192,9 +200,6 @@ context::initialize (int n_opts)
m_extra_output_kind = EXTRA_DIAGNOSTIC_OUTPUT_fixits_v2;
/* Silently ignore unrecognized values. */
}
- m_column_unit = DIAGNOSTICS_COLUMN_UNIT_DISPLAY;
- m_column_origin = 1;
- m_tabstop = 8;
m_escape_format = DIAGNOSTICS_ESCAPE_FORMAT_UNICODE;
m_fixits_change_set = nullptr;
m_diagnostic_groups.m_group_nesting_depth = 0;
@@ -207,6 +212,7 @@ context::initialize (int n_opts)
m_diagrams.m_theme = nullptr;
m_original_argv = nullptr;
m_diagnostic_buffer = nullptr;
+ m_logger = nullptr;
enum diagnostic_text_art_charset text_art_charset
= DIAGNOSTICS_TEXT_ART_CHARSET_EMOJI;
@@ -218,6 +224,27 @@ context::initialize (int n_opts)
text_art_charset = DIAGNOSTICS_TEXT_ART_CHARSET_ASCII;
}
set_text_art_charset (text_art_charset);
+
+ if (const char *name = getenv ("GCC_DIAGNOSTICS_LOG"))
+ {
+ if (name[0] != '\0')
+ {
+ /* Try to write a log to the named path. */
+ if (FILE *outfile = fopen (name, "w"))
+ m_logger = new logging::logger
+ (output_file (outfile, true,
+ label_text::take (xstrdup (name))));
+ }
+ else
+ /* Write a log to stderr. */
+ m_logger = new logging::logger
+ (output_file
+ (stderr, false,
+ label_text::borrow ("stderr")));
+ }
+
+ if (m_logger)
+ m_logger->log_printf ("diagnostics::context::initialize");
}
/* Maybe initialize the color support. We require clients to do this
@@ -284,6 +311,33 @@ context::urls_init (int value)
(m_reference_printer->get_url_format ());
}
+void
+context::set_show_nesting (bool val)
+{
+ for (auto sink_ : m_sinks)
+ if (sink_->follows_reference_printer_p ())
+ if (auto text_sink_ = sink_->dyn_cast_text_sink ())
+ text_sink_->set_show_nesting (val);
+}
+
+void
+context::set_show_nesting_locations (bool val)
+{
+ for (auto sink_ : m_sinks)
+ if (sink_->follows_reference_printer_p ())
+ if (auto text_sink_ = sink_->dyn_cast_text_sink ())
+ text_sink_->set_show_locations_in_nesting (val);
+}
+
+void
+context::set_show_nesting_levels (bool val)
+{
+ for (auto sink_ : m_sinks)
+ if (sink_->follows_reference_printer_p ())
+ if (auto text_sink_ = sink_->dyn_cast_text_sink ())
+ text_sink_->set_show_nesting_levels (val);
+}
+
/* Create the file_cache, if not already created, and tell it how to
translate files on input. */
void
@@ -298,6 +352,15 @@ context::initialize_input_context (diagnostic_input_charset_callback ccb,
void
context::finish ()
{
+ if (m_logger)
+ {
+ m_logger->log_printf ("diagnostics::context::finish");
+ /* We're cleaning up the logger before this function exits,
+ so we can't use auto_inc_depth here. */
+ m_logger->inc_depth ();
+ dump (m_logger->get_stream (), m_logger->get_indent ());
+ }
+
/* We might be handling a fatal error.
Close any active diagnostic groups, which may trigger flushing
sinks. */
@@ -337,8 +400,8 @@ context::finish ()
m_client_data_hooks = nullptr;
}
- delete m_option_mgr;
- m_option_mgr = nullptr;
+ delete m_option_id_mgr;
+ m_option_id_mgr = nullptr;
if (m_urlifier_stack)
{
@@ -350,38 +413,48 @@ context::finish ()
freeargv (m_original_argv);
m_original_argv = nullptr;
+
+ delete m_logger;
+ m_logger = nullptr;
}
/* Dump state of this diagnostics::context to OUT, for debugging. */
void
-context::dump (FILE *out) const
+context::dump (FILE *outfile, int indent) const
{
- fprintf (out, "diagnostics::context:\n");
- m_diagnostic_counters.dump (out, 2);
- fprintf (out, " reference printer:\n");
- m_reference_printer->dump (out, 4);
- fprintf (out, " output sinks:\n");
+ dumping::emit_heading (outfile, indent, "diagnostics::context");
+ m_diagnostic_counters.dump (outfile, indent + 2);
+ dumping::emit_heading (outfile, indent + 2, "reference printer");
+ if (m_reference_printer)
+ m_reference_printer->dump (outfile, indent + 4);
+ else
+ dumping::emit_none (outfile, indent + 4);
+ dumping::emit_heading (outfile, indent + 2, "output sinks");
if (m_sinks.length () > 0)
{
for (unsigned i = 0; i < m_sinks.length (); ++i)
{
- fprintf (out, " sink %i:\n", i);
- m_sinks[i]->dump (out, 4);
+ dumping::emit_indent (outfile, indent + 4);
+ const sink *s = m_sinks[i];
+ fprintf (outfile, "sink %i (", i);
+ s->dump_kind (outfile);
+ fprintf (outfile, "):\n");
+ s->dump (outfile, indent + 6);
}
}
else
- fprintf (out, " (none):\n");
- fprintf (out, " diagnostic buffer:\n");
+ dumping::emit_none (outfile, indent + 4);
+ dumping::emit_heading (outfile, indent + 2, "diagnostic buffer");
if (m_diagnostic_buffer)
- m_diagnostic_buffer->dump (out, 4);
+ m_diagnostic_buffer->dump (outfile, indent + 4);
else
- fprintf (out, " (none):\n");
- fprintf (out, " file cache:\n");
+ dumping::emit_none (outfile, indent + 4);
+ dumping::emit_heading (outfile, indent + 2, "file cache");
if (m_file_cache)
- m_file_cache->dump (out, 4);
+ m_file_cache->dump (outfile, indent + 4);
else
- fprintf (out, " (none):\n");
+ dumping::emit_none (outfile, indent + 4);
}
/* Return true if sufficiently severe diagnostics have been seen that
@@ -407,6 +480,9 @@ context::remove_all_output_sinks ()
void
context::set_sink (std::unique_ptr<sink> sink_)
{
+ DIAGNOSTICS_LOG_SCOPE_PRINTF0 (m_logger, "diagnostics::context::set_sink");
+ if (m_logger)
+ sink_->dump (m_logger->get_stream (), m_logger->get_indent ());
remove_all_output_sinks ();
m_sinks.safe_push (sink_.release ());
}
@@ -422,6 +498,9 @@ context::get_sink (size_t idx) const
void
context::add_sink (std::unique_ptr<sink> sink_)
{
+ DIAGNOSTICS_LOG_SCOPE_PRINTF0 (m_logger, "diagnostics::context::add_sink");
+ if (m_logger)
+ sink_->dump (m_logger->get_stream (), m_logger->get_indent ());
m_sinks.safe_push (sink_.release ());
}
@@ -465,11 +544,11 @@ context::set_original_argv (unique_argv original_argv)
}
void
-context::set_option_manager (std::unique_ptr<option_manager> mgr,
- unsigned lang_mask)
+context::set_option_id_manager (std::unique_ptr<option_id_manager> mgr,
+ unsigned lang_mask)
{
- delete m_option_mgr;
- m_option_mgr = mgr.release ();
+ delete m_option_id_mgr;
+ m_option_id_mgr = mgr.release ();
m_lang_mask = lang_mask;
}
@@ -626,6 +705,19 @@ get_text_for_kind (enum kind kind)
return diagnostic_kind_text[static_cast<int> (kind)];
}
+static const char *const diagnostic_kind_debug_text[] = {
+#define DEFINE_DIAGNOSTIC_KIND(K, T, C) (#K),
+#include "diagnostics/kinds.def"
+#undef DEFINE_DIAGNOSTIC_KIND
+ "must-not-happen"
+};
+
+const char *
+get_debug_string_for_kind (enum kind kind)
+{
+ return diagnostic_kind_debug_text[static_cast<int> (kind)];
+}
+
static const char *const diagnostic_kind_color[] = {
#define DEFINE_DIAGNOSTIC_KIND(K, T, C) (C),
#include "diagnostics/kinds.def"
@@ -671,11 +763,22 @@ convert_column_unit (file_cache &fc,
}
}
+/* Given an expanded_location, convert the column (which is in 1-based bytes)
+ to the requested units and origin. Return -1 if the column is
+ invalid (<= 0). */
+int
+column_options::convert_column (file_cache &fc,
+ expanded_location s) const
+{
+ int one_based_col = convert_column_unit (fc, m_column_unit, m_tabstop, s);
+ if (one_based_col <= 0)
+ return -1;
+ return one_based_col + (m_column_origin - 1);
+}
+
column_policy::column_policy (const context &dc)
: m_file_cache (dc.get_file_cache ()),
- m_column_unit (dc.m_column_unit),
- m_column_origin (dc.m_column_origin),
- m_tabstop (dc.m_tabstop)
+ m_column_options (dc.get_column_options ())
{
}
@@ -685,11 +788,7 @@ column_policy::column_policy (const context &dc)
int
column_policy::converted_column (expanded_location s) const
{
- int one_based_col = convert_column_unit (m_file_cache,
- m_column_unit, m_tabstop, s);
- if (one_based_col <= 0)
- return -1;
- return one_based_col + (m_column_origin - 1);
+ return m_column_options.convert_column (m_file_cache, s);
}
/* Return a string describing a location e.g. "foo.c:42:10". */
@@ -711,7 +810,7 @@ column_policy::get_location_text (const expanded_location &s,
col = converted_column (s);
}
- const char *line_col = maybe_line_and_column (line, col);
+ const char *line_col = text_sink::maybe_line_and_column (line, col);
return label_text::take (build_message_string ("%s%s%s:%s", locus_cs, file,
line_col, locus_ce));
}
@@ -1098,7 +1197,7 @@ context::get_any_inlining_info (diagnostic_info *diagnostic)
/* Retrieve the locations into which the expression about to be
diagnosed has been inlined, including those of all the callers
all the way down the inlining stack. */
- m_set_locations_cb (this, diagnostic);
+ m_set_locations_cb (*this, diagnostic);
else
{
/* When there's no callback use just the one location provided
@@ -1231,6 +1330,9 @@ context::emit_diagnostic_with_group_va (enum kind kind,
bool
context::report_diagnostic (diagnostic_info *diagnostic)
{
+ auto logger = get_logger ();
+ DIAGNOSTICS_LOG_SCOPE_PRINTF0 (logger, "diagnostics::context::report_diagnostic");
+
enum kind orig_diag_kind = diagnostic->m_kind;
/* Every call to report_diagnostic should be within a
@@ -1245,11 +1347,13 @@ context::report_diagnostic (diagnostic_info *diagnostic)
if (was_warning && m_inhibit_warnings)
{
inhibit_notes_in_group ();
+ if (m_logger)
+ m_logger->log_printf ("rejecting: inhibiting warnings");
return false;
}
if (m_adjust_diagnostic_info)
- m_adjust_diagnostic_info (this, diagnostic);
+ m_adjust_diagnostic_info (*this, diagnostic);
if (diagnostic->m_kind == kind::pedwarn)
{
@@ -1260,7 +1364,11 @@ context::report_diagnostic (diagnostic_info *diagnostic)
}
if (diagnostic->m_kind == kind::note && m_inhibit_notes_p)
- return false;
+ {
+ if (m_logger)
+ m_logger->log_printf ("rejecting: inhibiting notes");
+ return false;
+ }
/* If the user requested that warnings be treated as errors, so be
it. Note that we do this before the next block so that
@@ -1277,6 +1385,8 @@ context::report_diagnostic (diagnostic_info *diagnostic)
stack. . */
if (!diagnostic_enabled (diagnostic))
{
+ if (m_logger)
+ m_logger->log_printf ("rejecting: diagnostic not enabled");
inhibit_notes_in_group ();
return false;
}
@@ -1285,13 +1395,21 @@ context::report_diagnostic (diagnostic_info *diagnostic)
&& ((!m_warn_system_headers
&& diagnostic->m_iinfo.m_allsyslocs)
|| m_inhibit_warnings))
- /* Bail if the warning is not to be reported because all locations in the
- inlining stack (if there is one) are in system headers. */
- return false;
+ {
+ /* Bail if the warning is not to be reported because all locations in the
+ inlining stack (if there is one) are in system headers. */
+ if (m_logger)
+ m_logger->log_printf ("rejecting: warning in system header");
+ return false;
+ }
if (diagnostic->m_kind == kind::note && notes_inhibited_in_group ())
- /* Bail for all the notes in the diagnostic_group that started to inhibit notes. */
- return false;
+ {
+ /* Bail for all the notes in the diagnostic_group that started to inhibit notes. */
+ if (m_logger)
+ m_logger->log_printf ("rejecting: notes inhibited within group");
+ return false;
+ }
if (diagnostic->m_kind != kind::note && diagnostic->m_kind != kind::ice)
check_max_errors (false);
@@ -1352,8 +1470,13 @@ context::report_diagnostic (diagnostic_info *diagnostic)
/* Is this the initial diagnostic within the stack of groups? */
if (m_diagnostic_groups.m_emission_count == 0)
- for (auto sink_ : m_sinks)
- sink_->on_begin_group ();
+ {
+ DIAGNOSTICS_LOG_SCOPE_PRINTF0
+ (get_logger (),
+ "diagnostics::context: beginning group");
+ for (auto sink_ : m_sinks)
+ sink_->on_begin_group ();
+ }
m_diagnostic_groups.m_emission_count++;
va_list *orig_args = diagnostic->m_message.m_args_ptr;
@@ -1385,6 +1508,8 @@ context::report_diagnostic (diagnostic_info *diagnostic)
sink_->on_report_diagnostic (*diagnostic, orig_diag_kind);
}
+ const int tabstop = get_column_options ().m_tabstop;
+
switch (m_extra_output_kind)
{
default:
@@ -1393,14 +1518,14 @@ context::report_diagnostic (diagnostic_info *diagnostic)
print_parseable_fixits (get_file_cache (),
m_reference_printer, diagnostic->m_richloc,
DIAGNOSTICS_COLUMN_UNIT_BYTE,
- m_tabstop);
+ tabstop);
pp_flush (m_reference_printer);
break;
case EXTRA_DIAGNOSTIC_OUTPUT_fixits_v2:
print_parseable_fixits (get_file_cache (),
m_reference_printer, diagnostic->m_richloc,
DIAGNOSTICS_COLUMN_UNIT_DISPLAY,
- m_tabstop);
+ tabstop);
pp_flush (m_reference_printer);
break;
}
@@ -1510,6 +1635,13 @@ context::diagnostic_impl (rich_location *richloc,
const char *gmsgid,
va_list *ap, enum kind kind)
{
+ logging::log_function_params
+ (m_logger, "diagnostics::context::diagnostic_impl")
+ .log_param_option_id ("option_id", opt_id)
+ .log_param_kind ("kind", kind)
+ .log_param_string ("gmsgid", gmsgid);
+ logging::auto_inc_depth depth_sentinel (m_logger);
+
diagnostic_info diagnostic;
if (kind == diagnostics::kind::permerror)
{
@@ -1527,7 +1659,11 @@ context::diagnostic_impl (rich_location *richloc,
diagnostic.m_option_id = opt_id;
}
diagnostic.m_metadata = metadata;
- return report_diagnostic (&diagnostic);
+
+ bool ret = report_diagnostic (&diagnostic);
+ if (m_logger)
+ m_logger->log_bool_return ("diagnostics::context::diagnostic_impl", ret);
+ return ret;
}
/* Implement inform_n, warning_n, and error_n, as documented and
@@ -1541,6 +1677,13 @@ context::diagnostic_n_impl (rich_location *richloc,
const char *plural_gmsgid,
va_list *ap, enum kind kind)
{
+ logging::log_function_params
+ (m_logger, "diagnostics::context::diagnostic_n_impl")
+ .log_param_option_id ("option_id", opt_id)
+ .log_param_kind ("kind", kind)
+ .log_params_n_gmsgids (n, singular_gmsgid, plural_gmsgid);
+ logging::auto_inc_depth depth_sentinel (m_logger);
+
diagnostic_info diagnostic;
unsigned long gtn;
@@ -1557,7 +1700,11 @@ context::diagnostic_n_impl (rich_location *richloc,
if (kind == diagnostics::kind::warning)
diagnostic.m_option_id = opt_id;
diagnostic.m_metadata = metadata;
- return report_diagnostic (&diagnostic);
+
+ bool ret = report_diagnostic (&diagnostic);
+ if (m_logger)
+ m_logger->log_bool_return ("diagnostics::context::diagnostic_n_impl", ret);
+ return ret;
}
@@ -1659,8 +1806,13 @@ context::end_group ()
If any diagnostics were emitted, give the context a chance
to do something. */
if (m_diagnostic_groups.m_emission_count > 0)
- for (auto sink_ : m_sinks)
- sink_->on_end_group ();
+ {
+ DIAGNOSTICS_LOG_SCOPE_PRINTF0
+ (get_logger (),
+ "diagnostics::context::end_group: ending group");
+ for (auto sink_ : m_sinks)
+ sink_->on_end_group ();
+ }
m_diagnostic_groups.m_emission_count = 0;
}
/* We're popping one level, so might need to stop inhibiting notes. */
@@ -1682,9 +1834,15 @@ context::pop_nesting_level ()
}
void
+context::set_nesting_level (int new_level)
+{
+ m_diagnostic_groups.m_diagnostic_nesting_level = new_level;
+}
+
+void
sink::dump (FILE *out, int indent) const
{
- fprintf (out, "%*sprinter:\n", indent, "");
+ dumping::emit_heading (out, indent, "printer");
m_printer->dump (out, indent + 2);
}
@@ -1771,19 +1929,19 @@ counters::counters ()
void
counters::dump (FILE *out, int indent) const
{
- fprintf (out, "%*scounts:\n", indent, "");
+ dumping::emit_heading (out, indent, "counts");
bool none = true;
for (int i = 0; i < static_cast<int> (kind::last_diagnostic_kind); i++)
if (m_count_for_kind[i] > 0)
{
- fprintf (out, "%*s%s%i\n",
- indent + 2, "",
+ dumping::emit_indent (out, indent + 2);
+ fprintf (out, "%s%i\n",
get_text_for_kind (static_cast<enum kind> (i)),
m_count_for_kind[i]);
none = false;
}
if (none)
- fprintf (out, "%*s(none)\n", indent + 2, "");
+ dumping::emit_none (out, indent + 2);
}
void
@@ -2009,8 +2167,8 @@ assert_location_text (const char *expected_loc_text,
= DIAGNOSTICS_COLUMN_UNIT_BYTE)
{
diagnostics::selftest::test_context dc;
- dc.m_column_unit = column_unit;
- dc.m_column_origin = origin;
+ dc.get_column_options ().m_column_unit = column_unit;
+ dc.get_column_options ().m_column_origin = origin;
expanded_location xloc;
xloc.file = filename;
@@ -2046,8 +2204,8 @@ test_get_location_text ()
assert_location_text ("foo.c:42:", "foo.c", 42, 10, false);
assert_location_text ("foo.c:", "foo.c", 0, 10, false);
- diagnostics::maybe_line_and_column (INT_MAX, INT_MAX);
- diagnostics::maybe_line_and_column (INT_MIN, INT_MIN);
+ diagnostics::text_sink::maybe_line_and_column (INT_MAX, INT_MAX);
+ diagnostics::text_sink::maybe_line_and_column (INT_MIN, INT_MIN);
{
/* In order to test display columns vs byte columns, we need to create a
diff --git a/gcc/diagnostics/context.h b/gcc/diagnostics/context.h
index f47370b..9464f6a 100644
--- a/gcc/diagnostics/context.h
+++ b/gcc/diagnostics/context.h
@@ -23,7 +23,12 @@ along with GCC; see the file COPYING3. If not see
#include "lazily-created.h"
#include "unique-argv.h"
#include "diagnostics/option-classifier.h"
+#include "diagnostics/option-id-manager.h"
#include "diagnostics/context-options.h"
+#include "diagnostics/source-printing-options.h"
+#include "diagnostics/column-options.h"
+#include "diagnostics/counters.h"
+#include "diagnostics/logging.h"
namespace diagnostics {
@@ -81,84 +86,6 @@ typedef void (*text_finalizer_fn) (text_sink &,
const diagnostic_info *,
enum kind);
-/* Abstract base class for the diagnostic subsystem to make queries
- about command-line options. */
-
-class option_manager
-{
-public:
- virtual ~option_manager () {}
-
- /* Return 1 if option OPT_ID is enabled, 0 if it is disabled,
- or -1 if it isn't a simple on-off switch
- (or if the value is unknown, typically set later in target). */
- virtual int option_enabled_p (option_id opt_id) const = 0;
-
- /* Return malloced memory for the name of the option OPT_ID
- which enabled a diagnostic, originally of type ORIG_DIAG_KIND but
- possibly converted to DIAG_KIND by options such as -Werror.
- May return NULL if no name is to be printed.
- May be passed 0 as well as the index of a particular option. */
- virtual char *make_option_name (option_id opt_id,
- enum kind orig_diag_kind,
- enum kind diag_kind) const = 0;
-
- /* Return malloced memory for a URL describing the option that controls
- a diagnostic.
- May return NULL if no URL is available.
- May be passed 0 as well as the index of a particular option. */
- virtual char *make_option_url (option_id opt_id) const = 0;
-};
-
-/* A bundle of options relating to printing the user's source code
- (potentially with a margin, underlining, labels, etc). */
-
-struct source_printing_options
-{
- /* True if we should print the source line with a caret indicating
- the location.
- Corresponds to -fdiagnostics-show-caret. */
- bool enabled;
-
- /* Maximum width of the source line printed. */
- int max_width;
-
- /* Character used at the caret when printing source locations. */
- char caret_chars[rich_location::STATICALLY_ALLOCATED_RANGES];
-
- /* When printing source code, should the characters at carets and ranges
- be colorized? (assuming colorization is on at all).
- This should be true for frontends that generate range information
- (so that the ranges of code are colorized),
- and false for frontends that merely specify points within the
- source code (to avoid e.g. colorizing just the first character in
- a token, which would look strange). */
- bool colorize_source_p;
-
- /* When printing source code, should labelled ranges be printed?
- Corresponds to -fdiagnostics-show-labels. */
- bool show_labels_p;
-
- /* When printing source code, should there be a left-hand margin
- showing line numbers?
- Corresponds to -fdiagnostics-show-line-numbers. */
- bool show_line_numbers_p;
-
- /* If printing source code, what should the minimum width of the margin
- be? Line numbers will be right-aligned, and padded to this width.
- Corresponds to -fdiagnostics-minimum-margin-width=VALUE. */
- int min_margin_width;
-
- /* Usable by plugins; if true, print a debugging ruler above the
- source output. */
- bool show_ruler_p;
-
- /* When printing events in an inline path, should we print lines
- visualizing links between related events (e.g. for CFG paths)?
- Corresponds to -fdiagnostics-show-event-links. */
- bool show_event_links_p;
-};
-
/* A bundle of state for determining column numbers in diagnostics
(tab stops, whether to start at 0 or 1, etc).
Uses a file_cache to handle tabs. */
@@ -174,13 +101,11 @@ public:
bool show_column,
bool colorize) const;
- int get_tabstop () const { return m_tabstop; }
+ int get_tabstop () const { return m_column_options.m_tabstop; }
private:
file_cache &m_file_cache;
- enum diagnostics_column_unit m_column_unit;
- int m_column_origin;
- int m_tabstop;
+ column_options m_column_options;
};
/* A bundle of state for printing locations within diagnostics
@@ -291,28 +216,6 @@ private:
enum diagnostics_escape_format m_escape_format;
};
-/* A collection of counters of diagnostics, per-kind
- (e.g. "3 errors and 1 warning"), for use by both context
- and by diagnostics::buffer. */
-
-struct counters
-{
- counters ();
-
- void dump (FILE *out, int indent) const;
- void DEBUG_FUNCTION dump () const { dump (stderr, 0); }
-
- int get_count (enum kind kind) const
- {
- return m_count_for_kind[static_cast<size_t> (kind)];
- }
-
- void move_to (counters &dest);
- void clear ();
-
- int m_count_for_kind[static_cast<size_t> (kind::last_diagnostic_kind)];
-};
-
/* This class encapsulates the state of the diagnostics subsystem
as a whole (either directly, or via owned objects of other classes, to
avoid global variables).
@@ -334,7 +237,7 @@ struct counters
- an optional urlifier to inject URLs into formatted messages
- counting the number of diagnostics reported of each kind
(class diagnostics::counters)
- - calling out to a option_manager to determine if
+ - calling out to a option_id_manager to determine if
a particular warning is enabled or disabled
- tracking pragmas that enable/disable warnings in a range of
source code
@@ -362,7 +265,7 @@ public:
friend class text_sink;
friend class buffer;
- typedef void (*set_locations_callback_t) (context *,
+ typedef void (*set_locations_callback_t) (const context &,
diagnostic_info *);
void initialize (int n_opts);
@@ -373,8 +276,10 @@ public:
void finish ();
- void dump (FILE *out) const;
- void DEBUG_FUNCTION dump () const { dump (stderr); }
+ void dump (FILE *out, int indent) const;
+ void DEBUG_FUNCTION dump () const { dump (stderr, 0); }
+
+ logging::logger *get_logger () { return m_logger; }
bool execution_failed_p () const;
@@ -398,6 +303,7 @@ public:
void push_nesting_level ();
void pop_nesting_level ();
+ void set_nesting_level (int new_level);
bool warning_enabled_at (location_t loc, option_id opt_id);
@@ -432,18 +338,35 @@ public:
enum kind new_kind,
location_t where)
{
+ logging::log_function_params
+ (m_logger, "diagnostics::context::classify_diagnostics")
+ .log_param_option_id ("option_id", opt_id)
+ .log_param_kind ("new_kind", new_kind)
+ .log_param_location_t ("where", where);
+ logging::auto_inc_depth depth_sentinel (m_logger);
+
return m_option_classifier.classify_diagnostic (this,
opt_id,
new_kind,
where);
}
- void push_diagnostics (location_t where ATTRIBUTE_UNUSED)
+ void push_diagnostics (location_t where)
{
+ logging::log_function_params
+ (m_logger, "diagnostics::context::push_diagnostics")
+ .log_param_location_t ("where", where);
+ logging::auto_inc_depth depth_sentinel (m_logger);
+
m_option_classifier.push ();
}
void pop_diagnostics (location_t where)
{
+ logging::log_function_params
+ (m_logger, "diagnostics::context::pop_diagnostics")
+ .log_param_location_t ("where", where);
+ logging::auto_inc_depth depth_sentinel (m_logger);
+
m_option_classifier.pop (where);
}
@@ -489,6 +412,9 @@ public:
}
void set_show_path_depths (bool val) { m_show_path_depths = val; }
void set_show_option_requested (bool val) { m_show_option_requested = val; }
+ void set_show_nesting (bool val);
+ void set_show_nesting_locations (bool val);
+ void set_show_nesting_levels (bool val);
void set_max_errors (int val) { m_max_errors = val; }
void set_escape_format (enum diagnostics_escape_format val)
{
@@ -546,32 +472,32 @@ public:
/* Option-related member functions. */
inline bool option_enabled_p (option_id opt_id) const
{
- if (!m_option_mgr)
+ if (!m_option_id_mgr)
return true;
- return m_option_mgr->option_enabled_p (opt_id);
+ return m_option_id_mgr->option_enabled_p (opt_id);
}
inline char *make_option_name (option_id opt_id,
enum kind orig_diag_kind,
enum kind diag_kind) const
{
- if (!m_option_mgr)
+ if (!m_option_id_mgr)
return nullptr;
- return m_option_mgr->make_option_name (opt_id,
- orig_diag_kind,
- diag_kind);
+ return m_option_id_mgr->make_option_name (opt_id,
+ orig_diag_kind,
+ diag_kind);
}
inline char *make_option_url (option_id opt_id) const
{
- if (!m_option_mgr)
+ if (!m_option_id_mgr)
return nullptr;
- return m_option_mgr->make_option_url (opt_id);
+ return m_option_id_mgr->make_option_url (opt_id);
}
void
- set_option_manager (std::unique_ptr<option_manager> mgr,
- unsigned lang_mask);
+ set_option_id_manager (std::unique_ptr<option_id_manager> option_id_mgr,
+ unsigned lang_mask);
unsigned get_lang_mask () const
{
@@ -668,7 +594,7 @@ public:
}
void
- set_adjust_diagnostic_info_callback (void (*cb) (context *,
+ set_adjust_diagnostic_info_callback (void (*cb) (const context &,
diagnostic_info *))
{
m_adjust_diagnostic_info = cb;
@@ -688,6 +614,9 @@ public:
return m_source_printing;
}
+ column_options &get_column_options () { return m_column_options; }
+ const column_options &get_column_options () const { return m_column_options; }
+
void set_caret_max_width (int value);
private:
@@ -804,11 +733,11 @@ private:
/* Client hook to adjust properties of the given diagnostic that we're
about to issue, such as its kind. */
- void (*m_adjust_diagnostic_info)(context *, diagnostic_info *);
+ void (*m_adjust_diagnostic_info)(const context &, diagnostic_info *);
/* Owned by the context; this would be a std::unique_ptr if
context had a proper ctor. */
- option_manager *m_option_mgr;
+ option_id_manager *m_option_id_mgr;
unsigned m_lang_mask;
/* A stack of optional hooks for adding URLs to quoted text strings in
@@ -835,6 +764,7 @@ private:
bool m_inhibit_notes_p;
source_printing_options m_source_printing;
+ column_options m_column_options;
/* True if -freport-bug option is used. */
bool m_report_bug;
@@ -844,17 +774,6 @@ private:
-fdiagnostics-parseable-fixits and GCC_EXTRA_DIAGNOSTIC_OUTPUT. */
enum diagnostics_extra_output_kind m_extra_output_kind;
-public:
- /* What units to use when outputting the column number. */
- enum diagnostics_column_unit m_column_unit;
-
- /* The origin for the column number (1-based or 0-based typically). */
- int m_column_origin;
-
- /* The size of the tabstop for tab expansion. */
- int m_tabstop;
-
-private:
/* How should non-ASCII/non-printable bytes be escaped when
a diagnostic suggests escaping the source code on output. */
enum diagnostics_escape_format m_escape_format;
@@ -927,6 +846,11 @@ private:
later (if the buffer is flushed), moved to other buffers, or
discarded (if the buffer is cleared). */
buffer *m_diagnostic_buffer;
+
+ /* Owned by the context.
+ Debugging option: if non-NULL, report information to the logger
+ on what the context is doing. */
+ logging::logger *m_logger;
};
/* Client supplied function to announce a diagnostic
diff --git a/gcc/diagnostics/counters.h b/gcc/diagnostics/counters.h
new file mode 100644
index 0000000..42db3fe
--- /dev/null
+++ b/gcc/diagnostics/counters.h
@@ -0,0 +1,51 @@
+/* Counts of per-kind diagnostics.
+ Copyright (C) 2000-2025 Free Software Foundation, Inc.
+
+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
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_DIAGNOSTICS_COUNTERS_H
+#define GCC_DIAGNOSTICS_COUNTERS_H
+
+#include "diagnostics/kinds.h"
+
+namespace diagnostics {
+
+/* A collection of counters of diagnostics, per-kind
+ (e.g. "3 errors and 1 warning"), for use by both diagnostics::context
+ and by diagnostics::buffer. */
+
+struct counters
+{
+ counters ();
+
+ void dump (FILE *out, int indent) const;
+ void DEBUG_FUNCTION dump () const { dump (stderr, 0); }
+
+ int get_count (enum kind kind) const
+ {
+ return m_count_for_kind[static_cast<size_t> (kind)];
+ }
+
+ void move_to (counters &dest);
+ void clear ();
+
+ int m_count_for_kind[static_cast<size_t> (kind::last_diagnostic_kind)];
+};
+
+} // namespace diagnostics
+
+#endif /* ! GCC_DIAGNOSTICS_COUNTERS_H */
diff --git a/gcc/diagnostics/dumping.cc b/gcc/diagnostics/dumping.cc
new file mode 100644
index 0000000..1dbecf4
--- /dev/null
+++ b/gcc/diagnostics/dumping.cc
@@ -0,0 +1,102 @@
+/* Utilities for implementing "dump" functions for the diagnostics subsystem.
+ Copyright (C) 2025 Free Software Foundation, Inc.
+ Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+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
+<http://www.gnu.org/licenses/>. */
+
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "diagnostics/dumping.h"
+
+namespace diagnostics {
+namespace dumping {
+
+/* Emit indentation to OUTFILE for the start of a dump line. */
+
+void
+emit_indent (FILE *outfile, int indent)
+{
+ fprintf (outfile, "%*s", indent, "");
+}
+
+/* Emit an indented line to OUTFILE showing a heading. */
+
+void
+emit_heading (FILE *outfile, int indent,
+ const char *text)
+{
+ emit_indent (outfile, indent);
+ fprintf (outfile, "%s:\n", text);
+}
+
+/* Various functions that emit an indented line to OUTFILE
+ showing "label: value". */
+
+void
+emit_string_field (FILE *outfile, int indent,
+ const char *label, const char *value)
+{
+ emit_indent (outfile, indent);
+ fprintf (outfile, "%s: %s\n", label, value);
+}
+
+void
+emit_bool_field (FILE *outfile, int indent,
+ const char *label, bool value)
+{
+ emit_string_field (outfile, indent, label,
+ value ? "true" : "false");
+}
+
+void
+emit_size_t_field (FILE *outfile, int indent,
+ const char *label, size_t value)
+{
+ emit_indent (outfile, indent);
+ fprintf (outfile, "%s: " HOST_SIZE_T_PRINT_DEC "\n", label, value);
+}
+
+void
+emit_int_field (FILE *outfile, int indent,
+ const char *label, int value)
+{
+ emit_indent (outfile, indent);
+ fprintf (outfile, "%s: %i\n", label, value);
+}
+
+void
+emit_unsigned_field (FILE *outfile, int indent,
+ const char *label, unsigned value)
+{
+ emit_indent (outfile, indent);
+ fprintf (outfile, "%s: %u\n", label, value);
+}
+
+/* Emit an indented line to OUTFILE reading "(none)". */
+
+void
+emit_none (FILE *outfile, int indent)
+{
+ emit_indent (outfile, indent);
+ fprintf (outfile, "(none)\n");
+}
+
+
+} // namespace dumping {
+} // namespace diagnostics
diff --git a/gcc/diagnostics/dumping.h b/gcc/diagnostics/dumping.h
new file mode 100644
index 0000000..02f6485
--- /dev/null
+++ b/gcc/diagnostics/dumping.h
@@ -0,0 +1,50 @@
+/* Utilities for implementing "dump" functions for the diagnostics subsystem.
+ Copyright (C) 2025 Free Software Foundation, Inc.
+ Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+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
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_DIAGNOSTICS_DUMP_H
+#define GCC_DIAGNOSTICS_DUMP_H
+
+namespace diagnostics {
+namespace dumping {
+
+extern void emit_indent (FILE *outfile, int indent);
+extern void emit_heading (FILE *outfile, int indent,
+ const char *text);
+
+extern void emit_string_field (FILE *outfile, int indent,
+ const char *label, const char *value);
+extern void emit_bool_field (FILE *outfile, int indent,
+ const char *label, bool value);
+extern void emit_size_t_field (FILE *outfile, int indent,
+ const char *label, size_t value);
+extern void emit_int_field (FILE *outfile, int indent,
+ const char *label, int value);
+extern void emit_unsigned_field (FILE *outfile, int indent,
+ const char *label, unsigned value);
+
+extern void emit_none (FILE *outfile, int indent);
+
+#define DIAGNOSTICS_DUMPING_EMIT_BOOL_FIELD(FLAG) \
+ dumping::emit_bool_field (outfile, indent, #FLAG, FLAG)
+
+} // namespace dumping
+} // namespace diagnostics
+
+#endif /* ! GCC_DIAGNOSTICS_DUMP_H */
diff --git a/gcc/diagnostics/file-cache.cc b/gcc/diagnostics/file-cache.cc
index febeb03..0ec0679 100644
--- a/gcc/diagnostics/file-cache.cc
+++ b/gcc/diagnostics/file-cache.cc
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "cpplib.h"
#include "diagnostics/file-cache.h"
+#include "diagnostics/dumping.h"
#include "selftest.h"
#ifndef HAVE_ICONV
@@ -473,7 +474,8 @@ file_cache::dump (FILE *out, int indent) const
{
for (size_t i = 0; i < m_num_file_slots; ++i)
{
- fprintf (out, "%*sslot[%i]:\n", indent, "", (int)i);
+ dumping::emit_indent (out, indent);
+ fprintf (out, "slot[%i]:\n", (int)i);
m_file_slots[i].dump (out, indent + 2);
}
}
@@ -541,27 +543,38 @@ file_cache_slot::dump (FILE *out, int indent) const
{
if (!m_file_path)
{
- fprintf (out, "%*s(unused)\n", indent, "");
+ dumping::emit_indent (out, indent);
+ fprintf (out, "(unused)\n");
return;
}
- fprintf (out, "%*sfile_path: %s\n", indent, "", m_file_path);
- fprintf (out, "%*sfp: %p\n", indent, "", (void *)m_fp);
- fprintf (out, "%*sneeds_read_p: %i\n", indent, "", (int)needs_read_p ());
- fprintf (out, "%*sneeds_grow_p: %i\n", indent, "", (int)needs_grow_p ());
- fprintf (out, "%*suse_count: %i\n", indent, "", m_use_count);
- fprintf (out, "%*ssize: %zi\n", indent, "", m_size);
- fprintf (out, "%*snb_read: %zi\n", indent, "", m_nb_read);
- fprintf (out, "%*sstart_line_idx: %zi\n", indent, "", m_line_start_idx);
- fprintf (out, "%*sline_num: %zi\n", indent, "", m_line_num);
- fprintf (out, "%*smissing_trailing_newline: %i\n",
- indent, "", (int)m_missing_trailing_newline);
- fprintf (out, "%*sline records (%i):\n",
- indent, "", m_line_record.length ());
+ dumping::emit_string_field (out, indent, "file_path", m_file_path);
+ {
+ dumping::emit_indent (out, indent);
+ fprintf (out, "fp: %p\n", (void *)m_fp);
+ }
+ dumping::emit_bool_field (out, indent, "needs_read_p", needs_read_p ());
+ dumping::emit_bool_field (out, indent, "needs_grow_p", needs_grow_p ());
+ dumping::emit_unsigned_field (out, indent, "use_count", m_use_count);
+ dumping::emit_size_t_field (out, indent, "size", m_size);
+ dumping::emit_size_t_field (out, indent, "nb_read", m_nb_read);
+ dumping::emit_size_t_field (out, indent, "start_line_idx", m_line_start_idx);
+ dumping::emit_size_t_field (out, indent, "line_num", m_line_num);
+ dumping::emit_bool_field (out, indent, "missing_trailing_newline",
+ m_missing_trailing_newline);
+ {
+ dumping::emit_indent (out, indent);
+ fprintf (out, "line records (%i):\n", m_line_record.length ());
+ }
int idx = 0;
for (auto &line : m_line_record)
- fprintf (out, "%*s[%i]: line %zi: byte offsets: %zi-%zi\n",
- indent + 2, "",
- idx++, line.line_num, line.start_pos, line.end_pos);
+ {
+ dumping::emit_indent (out, indent);
+ fprintf (out, ("[%i]:"
+ " line " HOST_SIZE_T_PRINT_DEC ":"
+ " byte offsets: " HOST_SIZE_T_PRINT_DEC
+ "-" HOST_SIZE_T_PRINT_DEC "\n"),
+ idx++, line.line_num, line.start_pos, line.end_pos);
+ }
}
/* Returns TRUE iff the cache would need to be filled with data coming
diff --git a/gcc/diagnostics/html-sink.cc b/gcc/diagnostics/html-sink.cc
index 13d6309..64dcefe 100644
--- a/gcc/diagnostics/html-sink.cc
+++ b/gcc/diagnostics/html-sink.cc
@@ -33,6 +33,8 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostics/output-file.h"
#include "diagnostics/buffering.h"
#include "diagnostics/paths.h"
+#include "diagnostics/dumping.h"
+#include "diagnostics/logging.h"
#include "diagnostics/client-data-hooks.h"
#include "selftest.h"
#include "diagnostics/selftest-context.h"
@@ -61,6 +63,16 @@ html_generation_options::html_generation_options ()
{
}
+void
+html_generation_options::dump (FILE *outfile, int indent) const
+{
+ DIAGNOSTICS_DUMPING_EMIT_BOOL_FIELD (m_css);
+ DIAGNOSTICS_DUMPING_EMIT_BOOL_FIELD (m_javascript);
+ DIAGNOSTICS_DUMPING_EMIT_BOOL_FIELD (m_show_state_diagrams);
+ DIAGNOSTICS_DUMPING_EMIT_BOOL_FIELD (m_show_state_diagrams_sarif);
+ DIAGNOSTICS_DUMPING_EMIT_BOOL_FIELD (m_show_state_diagrams_dot_src);
+}
+
class html_builder;
/* Concrete buffering implementation subclass for HTML output. */
@@ -116,6 +128,8 @@ public:
const line_maps *line_maps,
const html_generation_options &html_gen_opts);
+ void dump (FILE *out, int indent) const;
+
void
set_main_input_filename (const char *name);
@@ -223,11 +237,12 @@ make_span (std::string class_)
void
html_sink_buffer::dump (FILE *out, int indent) const
{
- fprintf (out, "%*shtml_sink_buffer:\n", indent, "");
+ dumping::emit_heading (out, indent, "html_sink_buffer");
int idx = 0;
for (auto &result : m_results)
{
- fprintf (out, "%*sresult[%i]:\n", indent + 2, "", idx);
+ dumping::emit_indent (out, indent + 2);
+ fprintf (out, "result[%i]:\n", idx);
result->dump (out);
fprintf (out, "\n");
++idx;
@@ -470,6 +485,13 @@ html_builder::html_builder (context &dc,
}
void
+html_builder::dump (FILE *out, int indent) const
+{
+ dumping::emit_heading (out, indent, "HTML generation options");
+ m_html_gen_opts.dump (out, indent + 2);
+}
+
+void
html_builder::set_main_input_filename (const char *name)
{
gcc_assert (m_title_element);
@@ -539,7 +561,7 @@ html_builder::on_report_diagnostic (const diagnostic_info &diagnostic,
}
}
-// For ease of comparison with experimental-nesting-show-levels=yes
+// For ease of comparison with show-nesting-levels=yes
static void
add_nesting_level_attr (xml::element &element,
@@ -1018,10 +1040,11 @@ html_builder::make_element_for_diagnostic (const diagnostic_info &diagnostic,
// Add any metadata as a suffix to the message
if (diagnostic.m_metadata)
- {
- xp.add_text (" ");
- xp.append (make_element_for_metadata (*diagnostic.m_metadata));
- }
+ if (auto e = make_element_for_metadata (*diagnostic.m_metadata))
+ {
+ xp.add_text (" ");
+ xp.append (std::move (e));
+ }
// Add any option as a suffix to the message
@@ -1234,6 +1257,9 @@ html_builder::make_element_for_metadata (const metadata &m)
(make_metadata_element (std::move (label), std::move (url)));
}
+ if (span_metadata->m_children.empty ())
+ return nullptr;
+
return span_metadata;
}
@@ -1295,6 +1321,8 @@ html_builder::end_group ()
void
html_builder::flush_to_file (FILE *outf)
{
+ DIAGNOSTICS_LOG_SCOPE_PRINTF0 (m_context.get_logger (),
+ "diagnostics::html_builder::flush_to_file");
if (m_html_gen_opts.m_javascript)
{
gcc_assert (m_head_element);
@@ -1329,8 +1357,9 @@ public:
void dump (FILE *out, int indent) const override
{
- fprintf (out, "%*shtml_sink\n", indent, "");
sink::dump (out, indent);
+ dumping::emit_heading (out, indent, "html_builder");
+ m_builder.dump (out, indent + 2);
}
void
@@ -1363,6 +1392,9 @@ public:
on_report_diagnostic (const diagnostic_info &diagnostic,
enum kind orig_diag_kind) final override
{
+ DIAGNOSTICS_LOG_SCOPE_PRINTF0
+ (get_logger (),
+ "diagnostics::html_sink::on_report_diagnostic");
m_builder.on_report_diagnostic (diagnostic, orig_diag_kind, m_buffer);
}
void on_diagram (const diagram &d) final override
@@ -1435,12 +1467,10 @@ public:
{
m_builder.flush_to_file (m_output_file.get_open_file ());
}
- void dump (FILE *out, int indent) const override
+ void dump_kind (FILE *out) const override
{
- fprintf (out, "%*shtml_file_sink: %s\n",
- indent, "",
+ fprintf (out, "html_file_sink: %s",
m_output_file.get_filename ());
- sink::dump (out, indent);
}
bool machine_readable_stderr_p () const final override
{
@@ -1603,6 +1633,10 @@ private:
: html_sink (dc, line_maps, html_gen_opts)
{
}
+ void dump_kind (FILE *out) const final override
+ {
+ fprintf (out, "html_buffered_sink");
+ }
bool machine_readable_stderr_p () const final override
{
return true;
diff --git a/gcc/diagnostics/html-sink.h b/gcc/diagnostics/html-sink.h
index d86bde8..d25ceea 100644
--- a/gcc/diagnostics/html-sink.h
+++ b/gcc/diagnostics/html-sink.h
@@ -30,6 +30,8 @@ struct html_generation_options
{
html_generation_options ();
+ void dump (FILE *out, int indent) const;
+
bool m_css;
bool m_javascript;
diff --git a/gcc/diagnostics/kinds.h b/gcc/diagnostics/kinds.h
index 7b4a168..1357be5 100644
--- a/gcc/diagnostics/kinds.h
+++ b/gcc/diagnostics/kinds.h
@@ -38,6 +38,7 @@ enum class kind
};
extern const char *get_text_for_kind (enum diagnostics::kind);
+extern const char *get_debug_string_for_kind (enum diagnostics::kind);
extern const char *get_color_for_kind (enum diagnostics::kind);
} // namespace diagnostics
diff --git a/gcc/diagnostics/lazy-paths.cc b/gcc/diagnostics/lazy-paths.cc
index 4934651..f246eea 100644
--- a/gcc/diagnostics/lazy-paths.cc
+++ b/gcc/diagnostics/lazy-paths.cc
@@ -125,12 +125,12 @@ test_intraprocedural_path (pretty_printer *event_pp)
"double `free'");
}
-/* Implementation of diagnostics::option_manager for which all
+/* Implementation of diagnostics::option_id_manager for which all
options are disabled, for use in selftests.
Note that this is *not* called for option_id (0), which
means "always warn" */
-class all_warnings_disabled : public diagnostics::option_manager
+class all_warnings_disabled : public diagnostics::option_id_manager
{
public:
int option_enabled_p (diagnostics::option_id) const final override
@@ -168,7 +168,7 @@ test_emission (pretty_printer *event_pp)
is skipped. */
{
test_context dc;
- dc.set_option_manager (std::make_unique<all_warnings_disabled> (), 0);
+ dc.set_option_id_manager (std::make_unique<all_warnings_disabled> (), 0);
test_rich_location rich_loc (*event_pp);
ASSERT_FALSE (rich_loc.m_path.generated_p ());
diff --git a/gcc/diagnostics/logging.cc b/gcc/diagnostics/logging.cc
new file mode 100644
index 0000000..cfe23d5
--- /dev/null
+++ b/gcc/diagnostics/logging.cc
@@ -0,0 +1,72 @@
+/* Utilities for implementing "dump" functions for the diagnostics subsystem.
+ Copyright (C) 2025 Free Software Foundation, Inc.
+ Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+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
+<http://www.gnu.org/licenses/>. */
+
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "diagnostics/logging.h"
+
+namespace diagnostics {
+namespace logging {
+
+logger::logger (output_file outfile)
+: m_outfile (std::move (outfile)),
+ m_log_depth (0)
+{
+}
+
+void
+logger::log_printf (const char *fmt, ...)
+{
+ emit_indent ();
+
+ va_list ap;
+ va_start (ap, fmt);
+ vfprintf (get_stream (), fmt, ap);
+ va_end (ap);
+
+ emit_newline ();
+}
+
+void
+logger::log_bool_return (const char *function_name, bool retval)
+{
+ log_printf ("%s <- %s",
+ retval ? "true" : "false",
+ function_name);
+}
+
+/* Emit indentation to OUTFILE for the start of a log line. */
+
+void
+logger::emit_indent () const
+{
+ fprintf (get_stream (), "%*s", get_indent (), "");
+}
+
+void
+logger::emit_newline () const
+{
+ fputc ('\n', get_stream ());
+}
+
+} // namespace logging {
+} // namespace diagnostics
diff --git a/gcc/diagnostics/logging.h b/gcc/diagnostics/logging.h
new file mode 100644
index 0000000..34ca95b
--- /dev/null
+++ b/gcc/diagnostics/logging.h
@@ -0,0 +1,230 @@
+/* Debugging code for logging what the diagnostics subsystem is doing.
+ Copyright (C) 2025 Free Software Foundation, Inc.
+ Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+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
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_DIAGNOSTICS_LOGGING_H
+#define GCC_DIAGNOSTICS_LOGGING_H
+
+#include "diagnostics/output-file.h"
+#include "diagnostics/option-id.h"
+#include "diagnostics/kinds.h"
+
+namespace diagnostics {
+
+namespace logging {
+
+/* A class for emitting a temporal log of what the diagnostics subsystem
+ is doing, for debugging.
+ We can't use pretty_printer here as we could potentially be debugging
+ pretty-printing itself. */
+
+class logger
+{
+public:
+ logger (output_file outfile);
+
+ /* High-level functions that emit a line of text. */
+ void log_printf (const char *fmt, ...)
+ __attribute__ ((__format__ (printf, 2, 3)));
+ void log_bool_return (const char *function_name, bool retval);
+
+ /* Lower-level functions for building up a line of text. */
+ void emit_indent () const;
+ void emit_newline () const;
+
+ FILE *get_stream () const
+ {
+ return m_outfile.get_open_file ();
+ }
+
+ int get_indent () const { return m_log_depth * 2; }
+
+ void inc_depth () { m_log_depth++; }
+ void dec_depth () { m_log_depth--; }
+
+private:
+ output_file m_outfile;
+ int m_log_depth;
+};
+
+/* RAII class for pushing/popping depth within a logger. */
+
+class auto_inc_depth
+{
+public:
+ auto_inc_depth (logger *log)
+ : m_logger (log)
+ {
+ if (m_logger)
+ m_logger->inc_depth ();
+ }
+ ~auto_inc_depth ()
+ {
+ if (m_logger)
+ m_logger->dec_depth ();
+ }
+
+private:
+ logger *m_logger;
+};
+
+/* Class for debugging function call parameters. */
+
+class log_function_params
+{
+public:
+ log_function_params (logger *logger_, const char *name)
+ : m_logger (logger_),
+ m_first_param (true)
+ {
+ if (m_logger)
+ {
+ m_logger->emit_indent ();
+ fprintf (m_logger->get_stream (), "%s (", name);
+ }
+ }
+ ~log_function_params ()
+ {
+ if (m_logger)
+ {
+ fprintf (m_logger->get_stream (), ")");
+ m_logger->emit_newline ();
+ }
+ }
+
+ log_function_params &
+ log_param_string (const char *name, const char *value)
+ {
+ if (m_logger)
+ {
+ add_any_comma ();
+ fprintf (m_logger->get_stream (), "%s: \"%s\"", name, value);
+ }
+ return *this;
+ }
+
+ log_function_params &
+ log_param_location_t (const char *name, location_t value)
+ {
+ if (m_logger)
+ {
+ add_any_comma ();
+ fprintf (m_logger->get_stream (),
+ "%s: " HOST_SIZE_T_PRINT_HEX,
+ name, (fmt_size_t)value);
+ }
+ return *this;
+ }
+
+ log_function_params &
+ log_param_rich_location (const char *name, const rich_location *richloc)
+ {
+ if (m_logger)
+ {
+ add_any_comma ();
+ fprintf (m_logger->get_stream (),
+ "%s: %p",
+ name, const_cast<void *> ((const void *)richloc));
+ }
+ return *this;
+ }
+
+ log_function_params &
+ log_param_option_id (const char *name, diagnostics::option_id value)
+ {
+ if (m_logger)
+ {
+ add_any_comma ();
+ fprintf (m_logger->get_stream (), "%s: %i", name, value.m_idx);
+ }
+ return *this;
+ }
+
+ log_function_params &
+ log_param_kind (const char *name, enum diagnostics::kind value)
+ {
+ if (m_logger)
+ {
+ add_any_comma ();
+ fprintf (m_logger->get_stream (), "%s: %s",
+ name, get_debug_string_for_kind (value));
+ }
+ return *this;
+ }
+
+ log_function_params &
+ log_param_uhwi (const char *name, unsigned HOST_WIDE_INT value)
+ {
+ if (m_logger)
+ {
+ add_any_comma ();
+ fprintf (m_logger->get_stream (),
+ "%s: " HOST_WIDE_INT_PRINT_DEC,
+ name, value);
+ }
+ return *this;
+ }
+
+ log_function_params &
+ log_params_n_gmsgids (unsigned HOST_WIDE_INT n,
+ const char *singular_gmsgid,
+ const char *plural_gmsgid)
+ {
+ return log_param_uhwi ("n", n)
+ .log_param_string ("singular_gmsgid", singular_gmsgid)
+ .log_param_string ("plural_gmsgid", plural_gmsgid);
+ }
+
+private:
+ void
+ add_any_comma ()
+ {
+ gcc_assert (m_logger);
+ if (m_first_param)
+ m_first_param = false;
+ else
+ fprintf (m_logger->get_stream (), ", ");
+ }
+
+ logger *m_logger;
+ bool m_first_param;
+};
+
+} // namespace logging
+} // namespace diagnostics
+
+/* Various macros for logging a formatted line, and indenting
+ further log messages within a scope. */
+
+#define DIAGNOSTICS_LOG_SCOPE_PRINTF0(LOGGER, FMT) \
+ if (LOGGER) \
+ (LOGGER)->log_printf ((FMT)); \
+ diagnostics::logging::auto_inc_depth depth_sentinel (LOGGER);
+
+#define DIAGNOSTICS_LOG_SCOPE_PRINTF1(LOGGER, FMT, ARG0) \
+ if (LOGGER) \
+ (LOGGER)->log_printf ((FMT), (ARG0)); \
+ diagnostics::logging::auto_inc_depth depth_sentinel (LOGGER);
+
+#define DIAGNOSTICS_LOG_SCOPE_PRINTF2(LOGGER, FMT, ARG0, ARG1) \
+ if (LOGGER) \
+ (LOGGER)->log_printf ((FMT), (ARG0), (ARG1)); \
+ diagnostics::logging::auto_inc_depth depth_sentinel (LOGGER);
+
+#endif /* ! GCC_DIAGNOSTICS_LOGGING_H */
diff --git a/gcc/diagnostics/metadata.h b/gcc/diagnostics/metadata.h
index c28f982..39291ec 100644
--- a/gcc/diagnostics/metadata.h
+++ b/gcc/diagnostics/metadata.h
@@ -119,6 +119,8 @@ class metadata
const lazy_digraphs *m_lazy_digraphs;
};
+extern char *get_cwe_url (int cwe);
+
} // namespace diagnostics
#endif /* ! GCC_DIAGNOSTICS_METADATA_H */
diff --git a/gcc/diagnostics/option-id-manager.h b/gcc/diagnostics/option-id-manager.h
new file mode 100644
index 0000000..08add5b
--- /dev/null
+++ b/gcc/diagnostics/option-id-manager.h
@@ -0,0 +1,56 @@
+/* Hooks for giving client-specific meaning to option ids.
+ Copyright (C) 2000-2025 Free Software Foundation, Inc.
+
+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
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_DIAGNOSTICS_OPTION_ID_MANAGER_H
+#define GCC_DIAGNOSTICS_OPTION_ID_MANAGER_H
+
+namespace diagnostics {
+
+/* Abstract base class for the diagnostic subsystem to make queries
+ about command-line options. */
+
+class option_id_manager
+{
+public:
+ virtual ~option_id_manager () {}
+
+ /* Return 1 if option OPT_ID is enabled, 0 if it is disabled,
+ or -1 if it isn't a simple on-off switch
+ (or if the value is unknown, typically set later in target). */
+ virtual int option_enabled_p (option_id opt_id) const = 0;
+
+ /* Return malloced memory for the name of the option OPT_ID
+ which enabled a diagnostic, originally of type ORIG_DIAG_KIND but
+ possibly converted to DIAG_KIND by options such as -Werror.
+ May return NULL if no name is to be printed.
+ May be passed 0 as well as the index of a particular option. */
+ virtual char *make_option_name (option_id opt_id,
+ enum kind orig_diag_kind,
+ enum kind diag_kind) const = 0;
+
+ /* Return malloced memory for a URL describing the option that controls
+ a diagnostic.
+ May return NULL if no URL is available.
+ May be passed 0 as well as the index of a particular option. */
+ virtual char *make_option_url (option_id opt_id) const = 0;
+};
+
+} // namespace diagnostics
+
+#endif /* ! GCC_DIAGNOSTICS_OPTION_ID_MANAGER_H */
diff --git a/gcc/diagnostics/output-file.h b/gcc/diagnostics/output-file.h
index f936387..827adcd 100644
--- a/gcc/diagnostics/output-file.h
+++ b/gcc/diagnostics/output-file.h
@@ -21,6 +21,8 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_DIAGNOSTICS_OUTPUT_FILE_H
#define GCC_DIAGNOSTICS_OUTPUT_FILE_H
+#include "label-text.h"
+
namespace diagnostics {
/* RAII class for wrapping a FILE * that could be borrowed or owned,
diff --git a/gcc/diagnostics/output-spec.cc b/gcc/diagnostics/output-spec.cc
index 83f128c..e25d25a 100644
--- a/gcc/diagnostics/output-spec.cc
+++ b/gcc/diagnostics/output-spec.cc
@@ -182,10 +182,6 @@ public:
const scheme_name_and_params &parsed_arg) const final override;
private:
- static sarif_generation_options
- make_sarif_gen_opts (enum sarif_version version,
- bool state_graph);
-
static std::unique_ptr<sarif_serialization_format>
make_sarif_serialization_object (enum sarif_serialization_kind);
};
@@ -368,7 +364,7 @@ text_scheme_handler::make_sink (const context &ctxt,
const scheme_name_and_params &parsed_arg) const
{
bool show_color = pp_show_color (dc.get_reference_printer ());
- bool show_nesting = false;
+ bool show_nesting = true;
bool show_locations_in_nesting = true;
bool show_levels = false;
for (auto& iter : parsed_arg.m_kvs)
@@ -381,21 +377,21 @@ text_scheme_handler::make_sink (const context &ctxt,
return nullptr;
continue;
}
- if (key == "experimental-nesting")
+ if (key == "show-nesting")
{
if (!parse_bool_value (ctxt, unparsed_arg, key, value,
show_nesting))
return nullptr;
continue;
}
- if (key == "experimental-nesting-show-locations")
+ if (key == "show-nesting-locations")
{
if (!parse_bool_value (ctxt, unparsed_arg, key, value,
show_locations_in_nesting))
return nullptr;
continue;
}
- if (key == "experimental-nesting-show-levels")
+ if (key == "show-nesting-levels")
{
if (!parse_bool_value (ctxt, unparsed_arg, key, value, show_levels))
return nullptr;
@@ -405,9 +401,9 @@ text_scheme_handler::make_sink (const context &ctxt,
/* Key not found. */
auto_vec<const char *> known_keys;
known_keys.safe_push ("color");
- known_keys.safe_push ("experimental-nesting");
- known_keys.safe_push ("experimental-nesting-show-locations");
- known_keys.safe_push ("experimental-nesting-show-levels");
+ known_keys.safe_push ("show-nesting");
+ known_keys.safe_push ("show-nesting-locations");
+ known_keys.safe_push ("show-nesting-levels");
ctxt.report_unknown_key (unparsed_arg, key, get_scheme_name (),
known_keys);
return nullptr;
@@ -431,8 +427,7 @@ sarif_scheme_handler::make_sink (const context &ctxt,
label_text filename;
enum sarif_serialization_kind serialization_kind
= sarif_serialization_kind::json;
- enum sarif_version version = sarif_version::v2_1_0;
- bool state_graph = false;
+ sarif_generation_options sarif_gen_opts;
for (auto& iter : parsed_arg.m_kvs)
{
const std::string &key = iter.first;
@@ -463,17 +458,18 @@ sarif_scheme_handler::make_sink (const context &ctxt,
{{{"2.1", sarif_version::v2_1_0},
{"2.2-prerelease", sarif_version::v2_2_prerelease_2024_08_08}}};
- if (!parse_enum_value<enum sarif_version> (ctxt, unparsed_arg,
- key, value,
- value_names,
- version))
+ if (!parse_enum_value<enum sarif_version>
+ (ctxt, unparsed_arg,
+ key, value,
+ value_names,
+ sarif_gen_opts.m_version))
return nullptr;
continue;
}
if (key == "state-graphs")
{
if (!parse_bool_value (ctxt, unparsed_arg, key, value,
- state_graph))
+ sarif_gen_opts.m_state_graph))
return nullptr;
continue;
}
@@ -513,8 +509,6 @@ sarif_scheme_handler::make_sink (const context &ctxt,
if (!output_file_)
return nullptr;
- auto sarif_gen_opts = make_sarif_gen_opts (version, state_graph);
-
auto serialization_obj = make_sarif_serialization_object (serialization_kind);
auto sink = make_sarif_sink (dc,
@@ -525,16 +519,6 @@ sarif_scheme_handler::make_sink (const context &ctxt,
return sink;
}
-sarif_generation_options
-sarif_scheme_handler::make_sarif_gen_opts (enum sarif_version version,
- bool state_graph)
-{
- sarif_generation_options sarif_gen_opts;
- sarif_gen_opts.m_version = version;
- sarif_gen_opts.m_state_graph = state_graph;
- return sarif_gen_opts;
-}
-
std::unique_ptr<sarif_serialization_format>
sarif_scheme_handler::
make_sarif_serialization_object (enum sarif_serialization_kind kind)
@@ -557,12 +541,8 @@ html_scheme_handler::make_sink (const context &ctxt,
const char *unparsed_arg,
const scheme_name_and_params &parsed_arg) const
{
- bool css = true;
label_text filename;
- bool javascript = true;
- bool show_state_diagrams = false;
- bool show_state_diagrams_sarif = false;
- bool show_state_diagrams_dot_src = false;
+ html_generation_options html_gen_opts;
for (auto& iter : parsed_arg.m_kvs)
{
const std::string &key = iter.first;
@@ -570,7 +550,7 @@ html_scheme_handler::make_sink (const context &ctxt,
if (key == "css")
{
if (!parse_bool_value (ctxt, unparsed_arg, key, value,
- css))
+ html_gen_opts.m_css))
return nullptr;
continue;
}
@@ -582,28 +562,28 @@ html_scheme_handler::make_sink (const context &ctxt,
if (key == "javascript")
{
if (!parse_bool_value (ctxt, unparsed_arg, key, value,
- javascript))
+ html_gen_opts.m_javascript))
return nullptr;
continue;
}
if (key == "show-state-diagrams")
{
if (!parse_bool_value (ctxt, unparsed_arg, key, value,
- show_state_diagrams))
+ html_gen_opts.m_show_state_diagrams))
return nullptr;
continue;
}
if (key == "show-state-diagrams-dot-src")
{
if (!parse_bool_value (ctxt, unparsed_arg, key, value,
- show_state_diagrams_dot_src))
+ html_gen_opts.m_show_state_diagrams_dot_src))
return nullptr;
continue;
}
if (key == "show-state-diagrams-sarif")
{
if (!parse_bool_value (ctxt, unparsed_arg, key, value,
- show_state_diagrams_sarif))
+ html_gen_opts.m_show_state_diagrams_sarif))
return nullptr;
continue;
}
@@ -645,13 +625,6 @@ html_scheme_handler::make_sink (const context &ctxt,
if (!output_file_)
return nullptr;
- html_generation_options html_gen_opts;
- html_gen_opts.m_css = css;
- html_gen_opts.m_javascript = javascript;
- html_gen_opts.m_show_state_diagrams = show_state_diagrams;
- html_gen_opts.m_show_state_diagrams_sarif = show_state_diagrams_sarif;
- html_gen_opts.m_show_state_diagrams_dot_src = show_state_diagrams_dot_src;
-
auto sink = make_html_sink (dc,
*ctxt.get_affected_location_mgr (),
html_gen_opts,
diff --git a/gcc/diagnostics/sarif-sink.cc b/gcc/diagnostics/sarif-sink.cc
index 4738ae9..c85a35e 100644
--- a/gcc/diagnostics/sarif-sink.cc
+++ b/gcc/diagnostics/sarif-sink.cc
@@ -33,6 +33,8 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostics/paths.h"
#include "diagnostics/sink.h"
#include "diagnostics/buffering.h"
+#include "diagnostics/dumping.h"
+#include "diagnostics/logging.h"
#include "json.h"
#include "cpplib.h"
#include "diagnostics/logical-locations.h"
@@ -704,6 +706,14 @@ sarif_serialization_format_json::write_to_file (FILE *outf,
fprintf (outf, "\n");
}
+void
+sarif_serialization_format_json::dump (FILE *outfile, int indent) const
+{
+ dumping::emit_indent (outfile, indent);
+ fprintf (outfile, "json\n");
+ DIAGNOSTICS_DUMPING_EMIT_BOOL_FIELD (m_formatted);
+}
+
/* A class for managing SARIF output (for -fdiagnostics-format=sarif-stderr
and -fdiagnostics-format=sarif-file).
@@ -760,6 +770,8 @@ public:
const sarif_generation_options &sarif_gen_opts);
~sarif_builder ();
+ void dump (FILE *out, int indent) const;
+
void set_printer (pretty_printer &printer)
{
m_printer = &printer;
@@ -1674,7 +1686,7 @@ sarif_builder::sarif_builder (diagnostics::context &dc,
(std::make_unique<sarif_array_of_unique<sarif_logical_location>> ()),
m_run_graphs
(std::make_unique<sarif_array_of_unique<sarif_graph>> ()),
- m_tabstop (dc.m_tabstop),
+ m_tabstop (dc.get_column_options ().m_tabstop),
m_serialization_format (std::move (serialization_format)),
m_sarif_gen_opts (sarif_gen_opts),
m_next_result_idx (0),
@@ -1699,6 +1711,15 @@ sarif_builder::~sarif_builder ()
}
}
+void
+sarif_builder::dump (FILE *out, int indent) const
+{
+ dumping::emit_heading (out, indent, "serialization format");
+ m_serialization_format->dump (out, indent + 2);
+ dumping::emit_heading (out, indent, "SARIF generation options");
+ m_sarif_gen_opts.dump (out, indent + 2);
+}
+
/* Functions at which to stop the backtrace print. It's not
particularly helpful to print the callers of these functions. */
@@ -1924,6 +1945,8 @@ report_global_digraph (const lazily_created<digraphs::digraph> &ldg)
std::unique_ptr<sarif_log>
sarif_builder::flush_to_object ()
{
+ DIAGNOSTICS_LOG_SCOPE_PRINTF0 (m_context.get_logger (),
+ "diagnostics::sarif_builder::flush_to_object");
m_invocation_obj->prepare_to_flush (*this);
std::unique_ptr<sarif_log> top
= make_top_level_object (std::move (m_invocation_obj),
@@ -1939,6 +1962,8 @@ sarif_builder::flush_to_object ()
void
sarif_builder::flush_to_file (FILE *outf)
{
+ DIAGNOSTICS_LOG_SCOPE_PRINTF0 (m_context.get_logger (),
+ "diagnostics::sarif_builder::flush_to_file");
std::unique_ptr<sarif_log> top = flush_to_object ();
m_serialization_format->write_to_file (outf, *top);
}
@@ -3803,11 +3828,12 @@ sarif_builder::make_artifact_content_object (const char *text) const
void
sarif_sink_buffer::dump (FILE *out, int indent) const
{
- fprintf (out, "%*ssarif_sink_buffer:\n", indent, "");
+ dumping::emit_heading (out, indent, "sarif_sink_buffer");
int idx = 0;
for (auto &result : m_results)
{
- fprintf (out, "%*sresult[%i]:\n", indent + 2, "", idx);
+ dumping::emit_indent (out, indent + 2);
+ fprintf (out, "result[%i]:\n", idx);
result->dump (out, true);
fprintf (out, "\n");
++idx;
@@ -3862,8 +3888,9 @@ public:
void dump (FILE *out, int indent) const override
{
- fprintf (out, "%*ssarif_sink\n", indent, "");
sink::dump (out, indent);
+ dumping::emit_heading (out, indent, "sarif_builder");
+ m_builder.dump (out, indent + 2);
}
void
@@ -3918,6 +3945,9 @@ public:
on_report_diagnostic (const diagnostic_info &diagnostic,
enum kind orig_diag_kind) final override
{
+ DIAGNOSTICS_LOG_SCOPE_PRINTF0
+ (get_logger (),
+ "diagnostics::sarif_sink::on_report_diagnostic");
m_builder.on_report_diagnostic (diagnostic, orig_diag_kind, m_buffer);
}
void on_diagram (const diagram &d) final override
@@ -3973,6 +4003,10 @@ public:
{
m_builder.flush_to_file (m_stream);
}
+ void dump_kind (FILE *out) const override
+ {
+ fprintf (out, "sarif_stream_sink");
+ }
bool machine_readable_stderr_p () const final override
{
return m_stream == stderr;
@@ -4001,12 +4035,10 @@ public:
{
m_builder.flush_to_file (m_output_file.get_open_file ());
}
- void dump (FILE *out, int indent) const override
+ void dump_kind (FILE *out) const override
{
- fprintf (out, "%*ssarif_file_sink: %s\n",
- indent, "",
+ fprintf (out, "sarif_file_sink: %s",
m_output_file.get_filename ());
- sink::dump (out, indent);
}
bool machine_readable_stderr_p () const final override
{
@@ -4319,6 +4351,29 @@ sarif_generation_options::sarif_generation_options ()
{
}
+static const char *
+get_dump_string_for_sarif_version (enum sarif_version version)
+{
+ switch (version)
+ {
+ default:
+ gcc_unreachable ();
+ case sarif_version::v2_1_0:
+ return "v2_1_0";
+ case sarif_version::v2_2_prerelease_2024_08_08:
+ return "v2_2_prerelease_2024_08_08";
+ }
+}
+
+void
+sarif_generation_options::dump (FILE *outfile, int indent) const
+{
+ dumping::emit_string_field (outfile, indent,
+ "m_version",
+ get_dump_string_for_sarif_version (m_version));
+ DIAGNOSTICS_DUMPING_EMIT_BOOL_FIELD (m_state_graph);
+}
+
#if CHECKING_P
namespace selftest {
@@ -4406,10 +4461,10 @@ public:
test_sarif_diagnostic_context (const char *main_input_filename,
const sarif_generation_options &sarif_gen_opts)
{
- auto sink_ = std::make_unique<buffered_sink> (*this,
- line_table,
- true,
- sarif_gen_opts);
+ auto sink_ = std::make_unique<sarif_buffered_sink> (*this,
+ line_table,
+ true,
+ sarif_gen_opts);
m_sink = sink_.get (); // borrowed
init_sarif_sink (*this, std::move (sink_));
m_sink->set_main_input_filename (main_input_filename);
@@ -4424,10 +4479,10 @@ public:
sarif_result &get_result (size_t idx) { return m_sink->get_result (idx); }
private:
- class buffered_sink : public sarif_sink
+ class sarif_buffered_sink : public sarif_sink
{
public:
- buffered_sink (context &dc,
+ sarif_buffered_sink (context &dc,
const line_maps *line_maps,
bool formatted,
const sarif_generation_options &sarif_gen_opts)
@@ -4436,6 +4491,10 @@ private:
sarif_gen_opts)
{
}
+ void dump_kind (FILE *out) const final override
+ {
+ fprintf (out, "sarif_buffered_sink");
+ }
bool machine_readable_stderr_p () const final override
{
return false;
@@ -4446,7 +4505,7 @@ private:
}
};
- buffered_sink *m_sink; // borrowed
+ sarif_buffered_sink *m_sink; // borrowed
};
/* Test making a sarif_location for a complex rich_location
diff --git a/gcc/diagnostics/sarif-sink.h b/gcc/diagnostics/sarif-sink.h
index 9f8a73f..e6f897b 100644
--- a/gcc/diagnostics/sarif-sink.h
+++ b/gcc/diagnostics/sarif-sink.h
@@ -73,6 +73,7 @@ public:
virtual ~sarif_serialization_format () {}
virtual void write_to_file (FILE *outf,
const json::value &top) = 0;
+ virtual void dump (FILE *out, int indent) const = 0;
};
/* Concrete subclass for serializing SARIF as JSON. */
@@ -85,6 +86,7 @@ public:
{
}
void write_to_file (FILE *outf, const json::value &top) final override;
+ void dump (FILE *out, int indent) const final override;
private:
bool m_formatted;
@@ -108,6 +110,8 @@ struct sarif_generation_options
{
sarif_generation_options ();
+ void dump (FILE *out, int indent) const;
+
enum sarif_version m_version;
bool m_state_graph;
};
diff --git a/gcc/diagnostics/sink.h b/gcc/diagnostics/sink.h
index ac4e0fb64..aaa6c50 100644
--- a/gcc/diagnostics/sink.h
+++ b/gcc/diagnostics/sink.h
@@ -36,6 +36,9 @@ class sink
public:
virtual ~sink () {}
+ virtual text_sink *dyn_cast_text_sink () { return nullptr; }
+
+ virtual void dump_kind (FILE *out) const = 0;
virtual void dump (FILE *out, int indent) const;
/* Vfunc for notifying this format what the primary input file is,
@@ -87,6 +90,8 @@ public:
void DEBUG_FUNCTION dump () const { dump (stderr, 0); }
+ logging::logger *get_logger () { return m_context.get_logger (); }
+
protected:
sink (context &dc)
: m_context (dc),
diff --git a/gcc/diagnostics/source-printing-options.h b/gcc/diagnostics/source-printing-options.h
new file mode 100644
index 0000000..362b691
--- /dev/null
+++ b/gcc/diagnostics/source-printing-options.h
@@ -0,0 +1,76 @@
+/* Options relating to printing the user's source code.
+ Copyright (C) 2000-2025 Free Software Foundation, Inc.
+
+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
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_DIAGNOSTICS_SOURCE_PRINTING_OPTIONS_H
+#define GCC_DIAGNOSTICS_SOURCE_PRINTING_OPTIONS_H
+
+namespace diagnostics {
+
+/* A bundle of options relating to printing the user's source code
+ (potentially with a margin, underlining, labels, etc). */
+
+struct source_printing_options
+{
+ /* True if we should print the source line with a caret indicating
+ the location.
+ Corresponds to -fdiagnostics-show-caret. */
+ bool enabled;
+
+ /* Maximum width of the source line printed. */
+ int max_width;
+
+ /* Character used at the caret when printing source locations. */
+ char caret_chars[rich_location::STATICALLY_ALLOCATED_RANGES];
+
+ /* When printing source code, should the characters at carets and ranges
+ be colorized? (assuming colorization is on at all).
+ This should be true for frontends that generate range information
+ (so that the ranges of code are colorized),
+ and false for frontends that merely specify points within the
+ source code (to avoid e.g. colorizing just the first character in
+ a token, which would look strange). */
+ bool colorize_source_p;
+
+ /* When printing source code, should labelled ranges be printed?
+ Corresponds to -fdiagnostics-show-labels. */
+ bool show_labels_p;
+
+ /* When printing source code, should there be a left-hand margin
+ showing line numbers?
+ Corresponds to -fdiagnostics-show-line-numbers. */
+ bool show_line_numbers_p;
+
+ /* If printing source code, what should the minimum width of the margin
+ be? Line numbers will be right-aligned, and padded to this width.
+ Corresponds to -fdiagnostics-minimum-margin-width=VALUE. */
+ int min_margin_width;
+
+ /* Usable by plugins; if true, print a debugging ruler above the
+ source output. */
+ bool show_ruler_p;
+
+ /* When printing events in an inline path, should we print lines
+ visualizing links between related events (e.g. for CFG paths)?
+ Corresponds to -fdiagnostics-show-event-links. */
+ bool show_event_links_p;
+};
+
+} // namespace diagnostics
+
+#endif /* ! GCC_DIAGNOSTICS_SOURCE_PRINTING_OPTIONS_H */
diff --git a/gcc/diagnostics/source-printing.cc b/gcc/diagnostics/source-printing.cc
index 94b1c2d..aeda9ad 100644
--- a/gcc/diagnostics/source-printing.cc
+++ b/gcc/diagnostics/source-printing.cc
@@ -4412,7 +4412,7 @@ test_layout_x_offset_display_tab (const line_table_case &case_)
for (int tabstop = 1; tabstop != num_tabstops; ++tabstop)
{
test_context dc;
- dc.m_tabstop = tabstop;
+ dc.get_column_options ().m_tabstop = tabstop;
diagnostics::source_print_policy policy (dc);
layout test_layout (policy, richloc, nullptr);
colorizer col (*dc.get_reference_printer (),
@@ -4436,7 +4436,7 @@ test_layout_x_offset_display_tab (const line_table_case &case_)
for (int tabstop = 1; tabstop != num_tabstops; ++tabstop)
{
test_context dc;
- dc.m_tabstop = tabstop;
+ dc.get_column_options ().m_tabstop = tabstop;
static const int small_width = 24;
auto &source_printing_opts = dc.get_source_printing_options ();
source_printing_opts.max_width = small_width - 4;
@@ -6833,7 +6833,7 @@ test_tab_expansion (const line_table_case &case_)
everything too. */
{
test_context dc;
- dc.m_tabstop = tabstop;
+ dc.get_column_options ().m_tabstop = tabstop;
rich_location richloc (line_table,
linemap_position_for_column (line_table,
first_non_ws_byte_col));
@@ -6846,7 +6846,7 @@ test_tab_expansion (const line_table_case &case_)
as well. */
{
test_context dc;
- dc.m_tabstop = tabstop;
+ dc.get_column_options ().m_tabstop = tabstop;
rich_location richloc (line_table,
linemap_position_for_column (line_table,
right_quote_byte_col));
diff --git a/gcc/diagnostics/text-sink.cc b/gcc/diagnostics/text-sink.cc
index bcf91cf..d4cfb89 100644
--- a/gcc/diagnostics/text-sink.cc
+++ b/gcc/diagnostics/text-sink.cc
@@ -33,6 +33,8 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostics/diagram.h"
#include "diagnostics/text-sink.h"
#include "diagnostics/buffering.h"
+#include "diagnostics/dumping.h"
+#include "diagnostics/logging.h"
#include "text-art/theme.h"
/* Disable warnings about quoting issues in the pp_xxx calls below
@@ -76,7 +78,7 @@ text_sink_buffer::text_sink_buffer (sink &sink_)
void
text_sink_buffer::dump (FILE *out, int indent) const
{
- fprintf (out, "%*stext_sink_buffer:\n", indent, "");
+ dumping::emit_heading (out, indent, "text_sink_buffer");
m_output_buffer.dump (out, indent + 2);
}
@@ -156,18 +158,19 @@ text_sink::~text_sink ()
}
void
-text_sink::dump (FILE *out, int indent) const
-{
- fprintf (out, "%*stext_sink\n", indent, "");
- fprintf (out, "%*sm_follows_reference_printer: %s\n",
- indent, "",
- m_follows_reference_printer ? "true" : "false");
- sink::dump (out, indent);
- fprintf (out, "%*ssaved_output_buffer:\n", indent + 2, "");
+text_sink::dump (FILE *outfile, int indent) const
+{
+ DIAGNOSTICS_DUMPING_EMIT_BOOL_FIELD (m_follows_reference_printer);
+ DIAGNOSTICS_DUMPING_EMIT_BOOL_FIELD (m_show_nesting);
+ DIAGNOSTICS_DUMPING_EMIT_BOOL_FIELD (m_show_locations_in_nesting);
+ DIAGNOSTICS_DUMPING_EMIT_BOOL_FIELD (m_show_nesting_levels);
+
+ sink::dump (outfile, indent);
+ dumping::emit_heading (outfile, indent, "saved_output_buffer");
if (m_saved_output_buffer)
- m_saved_output_buffer->dump (out, indent + 4);
+ m_saved_output_buffer->dump (outfile, indent + 2);
else
- fprintf (out, "%*s(none):\n", indent + 4, "");
+ dumping::emit_none (outfile, indent + 2);
}
void
@@ -203,6 +206,11 @@ void
text_sink::on_report_diagnostic (const diagnostic_info &diagnostic,
enum kind orig_diag_kind)
{
+ auto logger = get_logger ();
+ DIAGNOSTICS_LOG_SCOPE_PRINTF0
+ (logger,
+ "diagnostics::text_sink::on_report_diagnostic");
+
pretty_printer *pp = get_printer ();
(*text_starter (&m_context)) (*this, &diagnostic);
@@ -612,7 +620,7 @@ text_sink::get_location_text (const expanded_location &s) const
The result is a statically allocated buffer. */
const char *
-maybe_line_and_column (int line, int col)
+text_sink::maybe_line_and_column (int line, int col)
{
static char result[32];
diff --git a/gcc/diagnostics/text-sink.h b/gcc/diagnostics/text-sink.h
index 5c60976..f280e72 100644
--- a/gcc/diagnostics/text-sink.h
+++ b/gcc/diagnostics/text-sink.h
@@ -51,6 +51,12 @@ public:
{}
~text_sink ();
+ text_sink *dyn_cast_text_sink () final override { return this; }
+
+ void dump_kind (FILE *out) const override
+ {
+ fprintf (out, "text_sink");
+ }
void dump (FILE *out, int indent) const override;
std::unique_ptr<per_sink_buffer>
@@ -127,6 +133,8 @@ public:
return m_source_printing;
}
+ static const char *maybe_line_and_column (int line, int col);
+
protected:
void print_any_cwe (const diagnostic_info &diagnostic);
void print_any_rules (const diagnostic_info &diagnostic);