diagnostics/color.o \
diagnostics/context.o \
diagnostics/digraphs.o \
+ diagnostics/dumping.o \
diagnostics/file-cache.o \
diagnostics/output-spec.o \
diagnostics/html-sink.o \
#include "diagnostic.h"
#include "diagnostics/buffering.h"
#include "diagnostics/sink.h"
+#include "diagnostics/dumping.h"
namespace diagnostics {
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
#include "diagnostics/logical-locations.h"
#include "diagnostics/buffering.h"
#include "diagnostics/file-cache.h"
+#include "diagnostics/dumping.h"
#ifdef HAVE_TERMIOS_H
# include <termios.h>
/* Dump state of this diagnostics::context to OUT, for debugging. */
void
-context::dump (FILE *out) const
+context::dump (FILE *outfile) 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, 0, "diagnostics::context");
+ m_diagnostic_counters.dump (outfile, 2);
+ dumping::emit_heading (outfile, 2, "reference printer");
+ m_reference_printer->dump (outfile, 4);
+ dumping::emit_heading (outfile, 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, 4);
+ const sink *s = m_sinks[i];
+ fprintf (outfile, "sink %i (", i);
+ s->dump_kind (outfile);
+ fprintf (outfile, "):\n");
+ s->dump (outfile, 6);
}
}
else
- fprintf (out, " (none):\n");
- fprintf (out, " diagnostic buffer:\n");
+ dumping::emit_none (outfile, 4);
+ dumping::emit_heading (outfile, 2, "diagnostic buffer");
if (m_diagnostic_buffer)
- m_diagnostic_buffer->dump (out, 4);
+ m_diagnostic_buffer->dump (outfile, 4);
else
- fprintf (out, " (none):\n");
- fprintf (out, " file cache:\n");
+ dumping::emit_none (outfile, 4);
+ dumping::emit_heading (outfile, 2, "file cache");
if (m_file_cache)
- m_file_cache->dump (out, 4);
+ m_file_cache->dump (outfile, 4);
else
- fprintf (out, " (none):\n");
+ dumping::emit_none (outfile, 4);
}
/* Return true if sufficiently severe diagnostics have been seen that
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);
}
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
--- /dev/null
+/* 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 specializattions that emit an indented line to OUTFILE
+ showing "label: value". */
+
+template <>
+void
+emit_field<const char *> (FILE *outfile, int indent,
+ const char *label, const char *value)
+{
+ emit_indent (outfile, indent);
+ fprintf (outfile, "%s: %s\n", label, value);
+}
+
+template <>
+void
+emit_field<char *> (FILE *outfile, int indent,
+ const char *label, char *value)
+{
+ emit_indent (outfile, indent);
+ fprintf (outfile, "%s: %s\n", label, value);
+}
+
+template <>
+void
+emit_field<bool> (FILE *outfile, int indent,
+ const char *label, bool value)
+{
+ emit_field<const char *> (outfile, indent, label,
+ value ? "true" : "false");
+}
+
+template <>
+void
+emit_field<size_t> (FILE *outfile, int indent,
+ const char *label, size_t value)
+{
+ emit_indent (outfile, indent);
+ fprintf (outfile, "%s: %zi\n", label, value);
+}
+
+template <>
+void
+emit_field<int> (FILE *outfile, int indent,
+ const char *label, int value)
+{
+ emit_indent (outfile, indent);
+ fprintf (outfile, "%s: %i\n", label, value);
+}
+
+template <>
+void
+emit_field<unsigned> (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
--- /dev/null
+/* 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);
+
+template <typename T>
+extern void emit_field (FILE *outfile, int indent,
+ const char *label, T value);
+
+extern void emit_none (FILE *outfile, int indent);
+
+#define DIAGNOSTICS_DUMPING_EMIT_FIELD(FLAG) \
+ dumping::emit_field (outfile, indent, #FLAG, FLAG)
+
+} // namespace dumping
+} // namespace diagnostics
+
+#endif /* ! GCC_DIAGNOSTICS_DUMP_H */
#include "coretypes.h"
#include "cpplib.h"
#include "diagnostics/file-cache.h"
+#include "diagnostics/dumping.h"
#include "selftest.h"
#ifndef HAVE_ICONV
{
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);
}
}
{
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_field (out, indent, "file_path", m_file_path);
+ {
+ dumping::emit_indent (out, indent);
+ fprintf (out, "fp: %p\n", (void *)m_fp);
+ }
+ dumping::emit_field (out, indent, "needs_read_p", needs_read_p ());
+ dumping::emit_field (out, indent, "needs_grow_p", needs_grow_p ());
+ dumping::emit_field (out, indent, "use_count", m_use_count);
+ dumping::emit_field (out, indent, "size", m_size);
+ dumping::emit_field (out, indent, "nb_read", m_nb_read);
+ dumping::emit_field (out, indent, "start_line_idx", m_line_start_idx);
+ dumping::emit_field (out, indent, "line_num", m_line_num);
+ dumping::emit_field (out, indent, "missing_trailing_newline",
+ (int)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 %zi: byte offsets: %zi-%zi\n",
+ idx++, line.line_num, line.start_pos, line.end_pos);
+ }
}
/* Returns TRUE iff the cache would need to be filled with data coming
#include "diagnostics/output-file.h"
#include "diagnostics/buffering.h"
#include "diagnostics/paths.h"
+#include "diagnostics/dumping.h"
#include "diagnostics/client-data-hooks.h"
#include "selftest.h"
#include "diagnostics/selftest-context.h"
{
}
+void
+html_generation_options::dump (FILE *outfile, int indent) const
+{
+ DIAGNOSTICS_DUMPING_EMIT_FIELD (m_css);
+ DIAGNOSTICS_DUMPING_EMIT_FIELD (m_javascript);
+ DIAGNOSTICS_DUMPING_EMIT_FIELD (m_show_state_diagrams);
+ DIAGNOSTICS_DUMPING_EMIT_FIELD (m_show_state_diagrams_sarif);
+ DIAGNOSTICS_DUMPING_EMIT_FIELD (m_show_state_diagrams_dot_src);
+}
+
class html_builder;
/* Concrete buffering implementation subclass for HTML output. */
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);
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;
}
}
+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)
{
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
{
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
{
: 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;
{
html_generation_options ();
+ void dump (FILE *out, int indent) const;
+
bool m_css;
bool m_javascript;
#include "diagnostics/paths.h"
#include "diagnostics/sink.h"
#include "diagnostics/buffering.h"
+#include "diagnostics/dumping.h"
#include "json.h"
#include "cpplib.h"
#include "diagnostics/logical-locations.h"
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_FIELD (m_formatted);
+}
+
/* A class for managing SARIF output (for -fdiagnostics-format=sarif-stderr
and -fdiagnostics-format=sarif-file).
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;
}
}
+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. */
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;
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
{
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;
{
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
{
{
}
+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_field (outfile, indent,
+ "m_version",
+ get_dump_string_for_sarif_version (m_version));
+ DIAGNOSTICS_DUMPING_EMIT_FIELD (m_state_graph);
+}
+
#if CHECKING_P
namespace selftest {
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);
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)
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;
}
};
- buffered_sink *m_sink; // borrowed
+ sarif_buffered_sink *m_sink; // borrowed
};
/* Test making a sarif_location for a complex rich_location
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. */
{
}
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;
{
sarif_generation_options ();
+ void dump (FILE *out, int indent) const;
+
enum sarif_version m_version;
bool m_state_graph;
};
public:
virtual ~sink () {}
+ 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,
#include "diagnostics/diagram.h"
#include "diagnostics/text-sink.h"
#include "diagnostics/buffering.h"
+#include "diagnostics/dumping.h"
#include "text-art/theme.h"
/* Disable warnings about quoting issues in the pp_xxx calls below
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);
}
}
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_FIELD (m_follows_reference_printer);
+ DIAGNOSTICS_DUMPING_EMIT_FIELD (m_show_nesting);
+ DIAGNOSTICS_DUMPING_EMIT_FIELD (m_show_locations_in_nesting);
+ DIAGNOSTICS_DUMPING_EMIT_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
{}
~text_sink ();
+ 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>