since otherwise the "no diagnostics" case would quote the main input
file, and doing so noticeably bloated the output seen in analyzer
integration testing (build directory went from 20G -> 21G). */
- get_or_create_artifact (main_input_filename_,
- diagnostic_artifact_role::analysis_target,
- false);
+ if (main_input_filename_)
+ get_or_create_artifact (main_input_filename_,
+ diagnostic_artifact_role::analysis_target,
+ false);
}
sarif_builder::~sarif_builder ()
const char *main_input_filename_,
bool formatted,
enum sarif_version version,
- const char *base_file_name)
+ diagnostic_output_file output_file)
: sarif_output_format (context, line_maps, main_input_filename_,
formatted, version),
- m_base_file_name (xstrdup (base_file_name))
+ m_output_file (std::move (output_file))
{
+ gcc_assert (m_output_file.get_open_file ());
+ gcc_assert (m_output_file.get_filename ());
}
~sarif_file_output_format ()
{
- char *filename = concat (m_base_file_name, ".sarif", nullptr);
- free (m_base_file_name);
- m_base_file_name = nullptr;
- FILE *outf = fopen (filename, "w");
- if (!outf)
- {
- const char *errstr = xstrerror (errno);
- fnotice (stderr, "error: unable to open '%s' for writing: %s\n",
- filename, errstr);
- free (filename);
- return;
- }
- m_builder.flush_to_file (outf);
- fclose (outf);
- free (filename);
+ m_builder.flush_to_file (m_output_file.get_open_file ());
}
bool machine_readable_stderr_p () const final override
{
}
private:
- char *m_base_file_name;
+ diagnostic_output_file m_output_file;
};
/* Print the start of an embedded link to PP, as per 3.11.6. */
void
diagnostic_output_format_init_sarif_file (diagnostic_context &context,
- const line_maps *line_maps,
+ line_maps *line_maps,
const char *main_input_filename_,
bool formatted,
enum sarif_version version,
const char *base_file_name)
{
gcc_assert (line_maps);
+
+ if (!base_file_name)
+ {
+ rich_location richloc (line_maps, UNKNOWN_LOCATION);
+ context.emit_diagnostic (DK_ERROR, richloc, nullptr, 0,
+ "unable to determine filename for SARIF output");
+ return;
+ }
+
+ label_text filename = label_text::take (concat (base_file_name,
+ ".sarif",
+ nullptr));
+ FILE *outf = fopen (filename.get (), "w");
+ if (!outf)
+ {
+ rich_location richloc (line_maps, UNKNOWN_LOCATION);
+ context.emit_diagnostic (DK_ERROR, richloc, nullptr, 0,
+ "unable to open %qs for SARIF output: %m",
+ filename.get ());
+ return;
+ }
+ diagnostic_output_file output_file (outf, true, std::move (filename));
diagnostic_output_format_init_sarif
(context,
::make_unique<sarif_file_output_format> (context,
main_input_filename_,
formatted,
version,
- base_file_name));
+ std::move (output_file)));
}
/* Populate CONTEXT in preparation for SARIF output to STREAM. */
#include "json.h"
#include "diagnostic-format.h"
+#include "diagnostic-output-file.h"
class logical_location;
enum sarif_version version);
extern void
diagnostic_output_format_init_sarif_file (diagnostic_context &context,
- const line_maps *line_maps,
+ line_maps *line_maps,
const char *main_input_filename_,
bool formatted,
enum sarif_version version,
--- /dev/null
+/* RAII class for managing FILE * for diagnostic formats.
+ Copyright (C) 2024 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_DIAGNOSTIC_OUTPUT_FILE_H
+#define GCC_DIAGNOSTIC_OUTPUT_FILE_H
+
+/* RAII class for wrapping a FILE * that could be borrowed or owned,
+ along with the underlying filename. */
+
+class diagnostic_output_file
+{
+public:
+ diagnostic_output_file (FILE *outf, bool owned, label_text filename)
+ : m_outf (outf),
+ m_owned (owned),
+ m_filename (std::move (filename))
+ {
+ gcc_assert (m_filename.get ());
+ if (m_owned)
+ gcc_assert (m_outf);
+ }
+ ~diagnostic_output_file ()
+ {
+ if (m_owned)
+ {
+ gcc_assert (m_outf);
+ fclose (m_outf);
+ }
+ }
+ diagnostic_output_file (const diagnostic_output_file &other) = delete;
+ diagnostic_output_file (diagnostic_output_file &&other)
+ : m_outf (other.m_outf),
+ m_owned (other.m_owned),
+ m_filename (std::move (other.m_filename))
+ {
+ other.m_outf = nullptr;
+ other.m_owned = false;
+
+ gcc_assert (m_filename.get ());
+ if (m_owned)
+ gcc_assert (m_outf);
+ }
+ diagnostic_output_file &
+ operator= (const diagnostic_output_file &other) = delete;
+ diagnostic_output_file &
+ operator= (diagnostic_output_file &&other) = delete;
+
+ operator bool () const { return m_outf != nullptr; }
+ FILE *get_open_file () const { return m_outf; }
+ const char *get_filename () const { return m_filename.get (); }
+
+private:
+ FILE *m_outf;
+ bool m_owned;
+ label_text m_filename;
+};
+
+#endif /* ! GCC_DIAGNOSTIC_OUTPUT_FILE_H */
return diagnostic_enabled (&diagnostic);
}
+/* Emit a diagnostic within a diagnostic group on this context. */
+
+bool
+diagnostic_context::emit_diagnostic (diagnostic_t kind,
+ rich_location &richloc,
+ const diagnostic_metadata *metadata,
+ diagnostic_option_id option_id,
+ const char *gmsgid, ...)
+{
+ begin_group ();
+
+ va_list ap;
+ va_start (ap, gmsgid);
+ bool ret = emit_diagnostic_va (kind, richloc, metadata, option_id,
+ gmsgid, &ap);
+ va_end (ap);
+
+ end_group ();
+
+ return ret;
+}
+
+/* As above, but taking a va_list *. */
+
+bool
+diagnostic_context::emit_diagnostic_va (diagnostic_t kind,
+ rich_location &richloc,
+ const diagnostic_metadata *metadata,
+ diagnostic_option_id option_id,
+ const char *gmsgid, va_list *ap)
+{
+ begin_group ();
+
+ bool ret = diagnostic_impl (&richloc, metadata, option_id,
+ gmsgid, ap, kind);
+
+ end_group ();
+
+ return ret;
+}
+
/* Report a diagnostic message (an error or a warning) as specified by
this diagnostic_context.
front-end independent format specifiers are exactly those described
return m_option_classifier.option_unspecified_p (option_id);
}
+ bool emit_diagnostic (diagnostic_t kind,
+ rich_location &richloc,
+ const diagnostic_metadata *metadata,
+ diagnostic_option_id option_id,
+ const char *gmsgid, ...)
+ ATTRIBUTE_GCC_DIAG(6,7);
+ bool emit_diagnostic_va (diagnostic_t kind,
+ rich_location &richloc,
+ const diagnostic_metadata *metadata,
+ diagnostic_option_id option_id,
+ const char *gmsgid, va_list *ap)
+ ATTRIBUTE_GCC_DIAG(6,0);
+
bool report_diagnostic (diagnostic_info *);
void check_max_errors (bool flush);