new file mode 100644
@@ -0,0 +1,602 @@
+/* A pure C API for emitting diagnostics.
+ Copyright (C) 2023 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 LIBDIAGNOSTICS_H
+#define LIBDIAGNOSTICS_H
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**********************************************************************
+ Macros for attributes.
+ These are all currently empty, and thus for the human reader rather than
+ the compiler.
+ **********************************************************************/
+
+#define LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL(ARG_NUM)
+
+#define LIBDIAGNOSTICS_PARAM_CAN_BE_NULL(ARG_NUM)
+
+#define LIBDIAGNOSTICS_PARAM_GCC_FORMAT_STRING(FMT_ARG_NUM, ARGS_ARG_NUM)
+
+
+/**********************************************************************
+ Data structures and types.
+ All structs within the API are opaque.
+ **********************************************************************/
+
+/* An opaque bundle of state for a client of the library.
+ Has zero of more "sinks" to which diagnostics are emitted.
+ Responsibilities:
+ - location-management
+ - caching of source file content
+ - patch generation. */
+typedef struct diagnostic_manager diagnostic_manager;
+
+/* Types relating to diagnostic output sinks. */
+
+typedef struct diagnostic_text_sink diagnostic_text_sink;
+
+/* An enum for determining if we should colorize a text output sink. */
+enum diagnostic_colorize
+{
+ DIAGNOSTIC_COLORIZE_IF_TTY,
+ DIAGNOSTIC_COLORIZE_NO,
+ DIAGNOSTIC_COLORIZE_YES
+};
+
+/* An enum for choosing the SARIF version for a SARIF output sink.
+ Eventually the SARIF output may support multiple SARIF versions. */
+
+enum diagnostic_sarif_version
+{
+ DIAGNOSTIC_SARIF_VERSION_2_1_0
+};
+
+/* Types relating to "physical" source locations i.e. locations within
+ specific files expressed via line/column. */
+
+/* Opaque type describing a particular input file. */
+typedef struct diagnostic_file diagnostic_file;
+
+/* Opaque type representing a key into a database of source locations within
+ a diagnostic_manager. Locations are created by various API calls into
+ the diagnostic_manager expressing source code points and ranges. They
+ persist until the diagnostic_manager is released, which cleans them
+ up.
+
+ NULL means "UNKNOWN", and can be returned by the manager as a
+ fallback when a problem occurs (e.g. too many locations).
+
+ A diagnostic_location can be a single point within the source code,
+ such as here (at the the '"' at the start of the string literal):
+
+ int i = "foo";
+ ^
+
+ or be a range with a start and finish, and a "caret" location.
+
+ a = (foo && bar)
+ ~~~~~^~~~~~~
+ where the caret here is at the first "&", and the start and finish
+ are at the parentheses. */
+
+typedef struct diagnostic_physical_location diagnostic_physical_location;
+
+/* Types for storing line and column information in text files.
+
+ Both libdiagnostics and emacs number source *lines* starting at 1, but
+ they have differing conventions for *columns*.
+
+ libdiagnostics uses a 1-based convention for source columns,
+ whereas Emacs's M-x column-number-mode uses a 0-based convention.
+
+ For example, an error in the initial, left-hand
+ column of source line 3 is reported by libdiagnostics as:
+
+ some-file.c:3:1: error: ...etc...
+
+ On navigating to the location of that error in Emacs
+ (e.g. via "next-error"),
+ the locus is reported in the Mode Line
+ (assuming M-x column-number-mode) as:
+
+ some-file.c 10% (3, 0)
+
+ i.e. "3:1:" in libdiagnostics corresponds to "(3, 0)" in Emacs. */
+
+typedef unsigned int diagnostic_line_num_t;
+typedef unsigned int diagnostic_column_num_t;
+
+/* An opaque type describing a "logical" source location
+ e.g. "within function 'foo'". */
+
+typedef struct diagnostic_logical_location diagnostic_logical_location;
+
+/* An enum for discriminating between different kinds of logical location
+ for a diagnostic.
+
+ Roughly corresponds to logicalLocation's "kind" property in SARIF v2.1.0
+ (section 3.33.7). */
+
+enum diagnostic_logical_location_kind_t
+{
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_FUNCTION,
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_MEMBER,
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_MODULE,
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_NAMESPACE,
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_TYPE,
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_RETURN_TYPE,
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_PARAMETER,
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_VARIABLE
+};
+
+/* A "diagnostic" is an opaque bundle of state for a particular
+ diagnostic that is being constructed in memory.
+
+ A diagnostic has a primary location and zero or more secondary
+ locations. For example:
+
+ a = (foo && bar)
+ ~~~~~^~~~~~~
+
+ This diagnostic has a single diagnostic_location, with the caret
+ at the first "&", and the start/finish at the parentheses.
+
+ Contrast with:
+
+ a = (foo && bar)
+ ~~~ ^~ ~~~
+
+ This diagnostic has three locations
+ - The primary location (at "&&") has its caret and start location at
+ the first "&" and end at the second "&.
+ - The secondary location for "foo" has its start and finish at the "f"
+ and "o" of "foo"; the caret is not flagged for display, but is perhaps at
+ the "f" of "foo".
+ - Similarly, the other secondary location (for "bar") has its start and
+ finish at the "b" and "r" of "bar"; the caret is not flagged for
+ display, but is perhaps at the"b" of "bar". */
+typedef struct diagnostic diagnostic;
+
+enum diagnostic_level
+{
+ DIAGNOSTIC_LEVEL_ERROR,
+ DIAGNOSTIC_LEVEL_WARNING,
+ DIAGNOSTIC_LEVEL_NOTE
+};
+
+/**********************************************************************
+ API entrypoints.
+ **********************************************************************/
+
+/* Create a new diagnostic_manager.
+ The client needs to call diagnostic_release_manager on it at some
+ point.
+ Note that no output sinks are created by default. */
+
+extern diagnostic_manager *
+diagnostic_manager_new (void);
+
+/* Release a diagnostic_manager.
+ This will flush output to all of the output sinks, and clean up. */
+
+extern void
+diagnostic_manager_release (diagnostic_manager *)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1);
+
+/* Optional metadata about the manager. */
+
+/* Set a string suitable for use as the value of the SARIF "name" property
+ (SARIF v2.1.0 section 3.19.8). */
+
+extern void
+diagnostic_manager_set_tool_name (diagnostic_manager *diag_mgr,
+ const char *value)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (2);
+
+/* Set a string suitable for use as the value of the SARIF "fullName" property
+ (SARIF v2.1.0 section 3.19.9). */
+
+extern void
+diagnostic_manager_set_full_name (diagnostic_manager *diag_mgr,
+ const char *value)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (2);
+
+/* Set a string suitable for use as the value of the SARIF "version" property
+ (SARIF v2.1.0 section 3.19.13). */
+
+extern void
+diagnostic_manager_set_version_string (diagnostic_manager *diag_mgr,
+ const char *value)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (2);
+
+/* Set a string suitable for use as the value of the SARIF "informationUri"
+ property (SARIF v2.1.0 section 3.19.17). */
+
+extern void
+diagnostic_manager_set_version_url (diagnostic_manager *diag_mgr,
+ const char *value)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (2);
+
+/* Destinations for diagnostics. */
+
+/* Add a new output sink to DIAG_MGR, which writes GCC-style diagnostics
+ to DST_STREAM.
+ Return a borrowed pointer to the sink, which is cleaned up when DIAG_MGR
+ is released.
+ The output for each diagnostic is written and flushed as each
+ diagnostic is finished. */
+
+extern diagnostic_text_sink *
+diagnostic_manager_add_text_sink (diagnostic_manager *diag_mgr,
+ FILE *dst_stream,
+ enum diagnostic_colorize colorize)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (2);
+
+/* Functions to manipulate text sinks. */
+
+/* Enable/disable printing of source text in the text sink.
+ Default: enabled. */
+
+extern void
+diagnostic_text_sink_set_source_printing_enabled (diagnostic_text_sink *text_sink,
+ int value)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1);
+
+/* Enable/disable colorization of the characters of source text
+ that are underlined.
+ This should be true for clients that generate range information
+ (so that the ranges of code are colorized),
+ and false for clients that merely specify points within the
+ source code (to avoid e.g. colorizing just the first character in
+ a token, which would look strange).
+ Default: enabled. */
+
+extern void
+diagnostic_text_sink_set_labelled_source_colorization_enabled (diagnostic_text_sink *text_sink,
+ int value)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1);
+
+/* Add a new output sink to DIAG_MGR, which writes SARIF of the given
+ version to DST_STREAM.
+ The output is not written until DIAG_MGR is released. */
+
+extern void
+diagnostic_manager_add_sarif_sink (diagnostic_manager *diag_mgr,
+ FILE *dst_stream,
+ enum diagnostic_sarif_version version)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (2);
+
+/* Write a patch to DST_STREAM consisting of all fix-it hints
+ on all diagnostics that have been finished on DIAG_MGR. */
+
+extern void
+diagnostic_manager_write_patch (diagnostic_manager *diag_mgr,
+ FILE *dst_stream)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (2);
+
+/* Location management. */
+
+/* Create a new diagnostic_file * for file NAME.
+
+ Repeated calls with matching NAMEs will return the
+ same object.
+
+ If SARIF_SOURCE_LANGUAGE is non-NULL, it specifies a "sourceLanguage"
+ value for the file when use when writing SARIF.
+ See SARIF v2.1.0 Appendix J for suggested values for various
+ programmming languages. */
+
+extern const diagnostic_file *
+diagnostic_manager_new_file (diagnostic_manager *diag_mgr,
+ const char *name,
+ const char *sarif_source_language)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (2)
+ LIBDIAGNOSTICS_PARAM_CAN_BE_NULL (3);
+
+// TODO
+extern void
+diagnostic_manager_debug_dump_file (diagnostic_manager *diag_mgr,
+ const diagnostic_file *file,
+ FILE *out)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBDIAGNOSTICS_PARAM_CAN_BE_NULL (2)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (3);
+
+/* Attempt to create a diagnostic_location representing
+ FILENAME:LINE_NUM, with no column information
+ (thus "the whole line"). */
+
+extern const diagnostic_physical_location *
+diagnostic_manager_new_location_from_file_and_line (diagnostic_manager *diag_mgr,
+ const diagnostic_file *file,
+ diagnostic_line_num_t line_num)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (2);
+
+/* Attempt to create a diagnostic_physical_location representing
+ FILENAME:LINE_NUM:COLUMN_NUM. */
+
+extern const diagnostic_physical_location *
+diagnostic_manager_new_location_from_file_line_column (diagnostic_manager *diag_mgr,
+ const diagnostic_file *file,
+ diagnostic_line_num_t line_num,
+ diagnostic_column_num_t column_num)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (2);
+
+/* Attempt to create a diagnostic_physical_location representing a
+ range within a source file, with a highlighted "caret" location.
+
+ All must be within the same file, but they can be on different lines.
+
+ For example, consider the location of the binary expression below:
+
+ ...|__________1111111112222222
+ ...|12345678901234567890123456
+ ...|
+ 521|int sum (int foo, int bar)
+ 522|{
+ 523| return foo + bar;
+ ...| ~~~~^~~~~
+ 524|}
+
+ The location's caret is at the "+", line 523 column 15, but starts
+ earlier, at the "f" of "foo" at column 11. The finish is at the "r"
+ of "bar" at column 19. */
+
+extern const diagnostic_physical_location *
+diagnostic_manager_new_location_from_range (diagnostic_manager *diag_mgr,
+ const diagnostic_physical_location *loc_caret,
+ const diagnostic_physical_location *loc_start,
+ const diagnostic_physical_location *loc_end)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBDIAGNOSTICS_PARAM_CAN_BE_NULL (2)
+ LIBDIAGNOSTICS_PARAM_CAN_BE_NULL (3)
+ LIBDIAGNOSTICS_PARAM_CAN_BE_NULL (4);
+
+// TODO
+extern void
+diagnostic_manager_debug_dump_location (const diagnostic_manager *diag_mgr,
+ const diagnostic_physical_location *loc,
+ FILE *out)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBDIAGNOSTICS_PARAM_CAN_BE_NULL (2)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (3);
+
+/* A bundle of state describing a logical location in the user's source,
+ such as "in function 'foo'".
+
+ SHORT_NAME can be NULL, or else a string suitable for use by
+ the SARIF logicalLocation "name" property (SARIF v2.1.0 section 3.33.4).
+
+ FULLY_QUALIFIED_NAME can be NULL or else a string suitable for use by
+ the SARIF logicalLocation "fullyQualifiedName" property
+ (SARIF v2.1.0 section 3.33.5).
+
+ DECORATED_NAME can be NULL or else a string suitable for use by
+ the SARIF logicalLocation "decoratedName" property
+ (SARIF v2.1.0 section 3.33.6). */
+
+extern const diagnostic_logical_location *
+diagnostic_manager_new_logical_location (diagnostic_manager *diag_mgr,
+ enum diagnostic_logical_location_kind_t kind,
+ const diagnostic_logical_location *parent,
+ const char *short_name,
+ const char *fully_qualified_name,
+ const char *decorated_name)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBDIAGNOSTICS_PARAM_CAN_BE_NULL (3)
+ LIBDIAGNOSTICS_PARAM_CAN_BE_NULL (4)
+ LIBDIAGNOSTICS_PARAM_CAN_BE_NULL (5)
+ LIBDIAGNOSTICS_PARAM_CAN_BE_NULL (6);
+
+// TODO
+extern void
+diagnostic_manager_debug_dump_logical_location (const diagnostic_manager *diag_mgr,
+ const diagnostic_logical_location *loc,
+ FILE *out)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBDIAGNOSTICS_PARAM_CAN_BE_NULL (2)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (3);
+
+/* Diagnostic groups. */
+
+// FIXME: docs
+
+extern void
+diagnostic_manager_begin_group (diagnostic_manager *diag_mgr)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1);
+
+extern void
+diagnostic_manager_end_group (diagnostic_manager *diag_mgr)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1);
+
+/* Step-by-step creation of a diagnostic. */
+
+extern diagnostic *
+diagnostic_begin (diagnostic_manager *diag_mgr,
+ enum diagnostic_level level)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1);
+
+#if 0
+// FIXME: TODO
+extern void
+diagnostic_set_option (diagnostic *diag,
+ const char *option,
+ const char *url);
+#endif
+
+/* Associate this diagnostic with the given ID within
+ the Common Weakness Enumeration. */
+
+extern void
+diagnostic_set_cwe (diagnostic *diag,
+ unsigned cwe_id)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1);
+
+/* Associate this diagnostic with a particular rule that has been violated
+ (such as in a coding standard, or within a specification).
+ The rule must have at least one of a title and a URL, but these
+ can be NULL.
+ A diagnostic can be associated with zero or more rules. */
+
+extern void
+diagnostic_add_rule (diagnostic *diag,
+ const char *title,
+ const char *url)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBDIAGNOSTICS_PARAM_CAN_BE_NULL (2)
+ LIBDIAGNOSTICS_PARAM_CAN_BE_NULL (3);
+
+/* Set the primary location of DIAG. */
+
+extern void
+diagnostic_set_location (diagnostic *diag,
+ const diagnostic_physical_location * loc)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBDIAGNOSTICS_PARAM_CAN_BE_NULL (2);
+
+/* Set the primary location of DIAG, with a label. */
+
+extern void
+diagnostic_set_location_with_label (diagnostic *diag,
+ const diagnostic_physical_location *loc,
+ const char *fmt, ...)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBDIAGNOSTICS_PARAM_CAN_BE_NULL (2)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (3);
+
+/* Add a secondary location to DIAG. */
+
+extern void
+diagnostic_add_location (diagnostic *diag,
+ const diagnostic_physical_location * loc)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1);
+
+/* Add a secondary location to DIAG, with a label. */
+
+extern void
+diagnostic_add_location_with_label (diagnostic *diag,
+ const diagnostic_physical_location *loc,
+ const char *text)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBDIAGNOSTICS_PARAM_CAN_BE_NULL (2)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (3);
+
+/* Set the logical location of DIAG. */
+
+extern void
+diagnostic_set_logical_location (diagnostic *diag,
+ const diagnostic_logical_location *logical_loc)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBDIAGNOSTICS_PARAM_CAN_BE_NULL (2);
+
+/* Fix-it hints. */
+
+extern void
+diagnostic_add_fix_it_hint_insert_before (diagnostic *diag,
+ const diagnostic_physical_location *loc,
+ const char *addition)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBDIAGNOSTICS_PARAM_CAN_BE_NULL (2)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (3);
+
+extern void
+diagnostic_add_fix_it_hint_insert_after (diagnostic *diag,
+ const diagnostic_physical_location *loc,
+ const char *addition)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBDIAGNOSTICS_PARAM_CAN_BE_NULL (2)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (3);
+
+extern void
+diagnostic_add_fix_it_hint_replace (diagnostic *diag,
+ const diagnostic_physical_location *loc,
+ const char *replacement)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBDIAGNOSTICS_PARAM_CAN_BE_NULL (2)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (3);
+
+extern void
+diagnostic_add_fix_it_hint_delete (diagnostic *diag,
+ const diagnostic_physical_location *loc)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBDIAGNOSTICS_PARAM_CAN_BE_NULL (2);
+
+/* Emit DIAG to all sinks of its manager, and release DIAG.
+ Use FMT for the message.
+ TODO: this uses gcc's pretty-print format, which is *not* printf.
+ TODO: who is responsible for putting FMT through gettext? */
+
+extern void
+diagnostic_finish (diagnostic *diag, const char *fmt, ...)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (2)
+ LIBDIAGNOSTICS_PARAM_GCC_FORMAT_STRING (2, 3);
+
+// FIXME
+
+extern void
+diagnostic_finish_va (diagnostic *diag, const char *fmt, va_list *args)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (1)
+ LIBDIAGNOSTICS_PARAM_MUST_BE_NON_NULL (2)
+ LIBDIAGNOSTICS_PARAM_GCC_FORMAT_STRING (2, 0);
+
+// FIXME: we might want one that handles plurals
+#if 0
+extern void
+diagnostic_finish_n (diagnostic_manager *diag_mgr,
+ int n,
+ const char *singular_fmt,
+ const char *plural_fmt,
+ ...);
+#endif
+
+/* TODO:
+
+ DEFERRED:
+ - thread-safety
+ - plural forms
+ - enum about what a "column number" means (bytes, unichars, etc)
+ - locations within binary files
+ - options and URLs for warnings
+ - enable/disable of warnings by kind
+ - execution paths associated with/triggering a problem
+ - plugin metadata. */
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* LIBDIAGNOSTICS_H */
new file mode 100644
@@ -0,0 +1,55 @@
+/* Usage example of dump API. */
+
+#include "libdiagnostics.h"
+
+const int line_num = 42;
+
+int
+main ()
+{
+ diagnostic_manager *diag_mgr = diagnostic_manager_new ();
+
+ const diagnostic_file *file = diagnostic_manager_new_file (diag_mgr, "foo.c", "c");
+
+ fprintf (stderr, "file: ");
+ diagnostic_manager_debug_dump_file (diag_mgr, file, stderr);
+ fprintf (stderr, "\n");
+
+ const diagnostic_physical_location *loc_start
+ = diagnostic_manager_new_location_from_file_line_column (diag_mgr, file, line_num, 8);
+ const diagnostic_physical_location *loc_end
+ = diagnostic_manager_new_location_from_file_line_column (diag_mgr, file, line_num, 19);
+ const diagnostic_physical_location *loc_range
+ = diagnostic_manager_new_location_from_range (diag_mgr,
+ loc_start,
+ loc_start,
+ loc_end);
+
+ fprintf (stderr, "loc_start: ");
+ diagnostic_manager_debug_dump_location (diag_mgr, loc_start, stderr);
+ fprintf (stderr, "\n");
+
+ fprintf (stderr, "loc_end: ");
+ diagnostic_manager_debug_dump_location (diag_mgr, loc_end, stderr);
+ fprintf (stderr, "\n");
+
+ fprintf (stderr, "loc_range: ");
+ diagnostic_manager_debug_dump_location (diag_mgr, loc_range, stderr);
+ fprintf (stderr, "\n");
+
+
+ const diagnostic_logical_location *logical_loc
+ = diagnostic_manager_new_logical_location (diag_mgr,
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_FUNCTION,
+ NULL, /* parent */
+ "test_short_name",
+ "test_qualified_name",
+ "test_decorated_name");
+
+ fprintf (stderr, "logical_loc: ");
+ diagnostic_manager_debug_dump_logical_location (diag_mgr, logical_loc, stderr);
+ fprintf (stderr, "\n");
+
+ diagnostic_manager_release (diag_mgr);
+ return 0;
+};
new file mode 100644
@@ -0,0 +1,57 @@
+/* Example of emitting an error with an associated note.
+
+ Intended output is similar to:
+
+PATH/test-error-with-note.c:6: error: can't find 'foo'
+ 6 | PRINT "hello world!";
+ | ^~~~~~~~~~~~
+PATH/test-error-with-note.c:6: note: have you looked behind the couch?
+
+ along with the equivalent in SARIF. */
+
+#include "libdiagnostics.h"
+
+/*
+_________111111111122
+123456789012345678901
+PRINT "hello world!";
+*/
+const int line_num = __LINE__ - 2;
+
+int
+main ()
+{
+ diagnostic_manager *diag_mgr = diagnostic_manager_new ();
+
+ diagnostic_manager_add_text_sink (diag_mgr, stderr,
+ DIAGNOSTIC_COLORIZE_IF_TTY);
+ diagnostic_manager_add_sarif_sink (diag_mgr, stderr,
+ DIAGNOSTIC_SARIF_VERSION_2_1_0);
+
+ const diagnostic_file *file = diagnostic_manager_new_file (diag_mgr, __FILE__, "c");
+ const diagnostic_physical_location *loc_start
+ = diagnostic_manager_new_location_from_file_line_column (diag_mgr, file, line_num, 8);
+ const diagnostic_physical_location *loc_end
+ = diagnostic_manager_new_location_from_file_line_column (diag_mgr, file, line_num, 19);
+ const diagnostic_physical_location *loc_range
+ = diagnostic_manager_new_location_from_range (diag_mgr,
+ loc_start,
+ loc_start,
+ loc_end);
+
+ diagnostic_manager_begin_group (diag_mgr);
+
+ diagnostic *err = diagnostic_begin (diag_mgr,
+ DIAGNOSTIC_LEVEL_ERROR);
+ diagnostic_set_location (err, loc_range);
+ diagnostic_finish (err, "can't find %qs", "foo");
+
+ diagnostic *note = diagnostic_begin (diag_mgr, DIAGNOSTIC_LEVEL_NOTE);
+ diagnostic_set_location (note, loc_range);
+ diagnostic_finish (note, "have you looked behind the couch?");
+
+ diagnostic_manager_end_group (diag_mgr);
+
+ diagnostic_manager_release (diag_mgr);
+ return 0;
+};
new file mode 100644
@@ -0,0 +1,49 @@
+/* Example of emitting an error.
+
+ Intended output is similar to:
+
+PATH/test-error-with-note.c:6: error: can't find 'foo'
+ 6 | PRINT "hello world!";
+ | ^~~~~~~~~~~~
+
+ along with the equivalent in SARIF. */
+
+#include "libdiagnostics.h"
+
+/*
+_________111111111122
+123456789012345678901
+PRINT "hello world!";
+*/
+const int line_num = __LINE__ - 2;
+
+int
+main ()
+{
+ diagnostic_manager *diag_mgr = diagnostic_manager_new ();
+
+ diagnostic_manager_add_text_sink (diag_mgr, stderr,
+ DIAGNOSTIC_COLORIZE_IF_TTY);
+ diagnostic_manager_add_sarif_sink (diag_mgr, stderr,
+ DIAGNOSTIC_SARIF_VERSION_2_1_0);
+
+ const diagnostic_file *file = diagnostic_manager_new_file (diag_mgr, __FILE__, "c");
+ const diagnostic_physical_location *loc_start
+ = diagnostic_manager_new_location_from_file_line_column (diag_mgr, file, line_num, 8);
+ const diagnostic_physical_location *loc_end
+ = diagnostic_manager_new_location_from_file_line_column (diag_mgr, file, line_num, 19);
+ const diagnostic_physical_location *loc_range
+ = diagnostic_manager_new_location_from_range (diag_mgr,
+ loc_start,
+ loc_start,
+ loc_end);
+
+ diagnostic *d = diagnostic_begin (diag_mgr,
+ DIAGNOSTIC_LEVEL_ERROR);
+ diagnostic_set_location (d, loc_range);
+
+ diagnostic_finish (d, "can't find %qs", "foo");
+
+ diagnostic_manager_release (diag_mgr);
+ return 0;
+};
new file mode 100644
@@ -0,0 +1,49 @@
+/* Example of a fix-it hint, including patch generation.
+
+ Intended output is similar to:
+
+PATH/test-fix-it-hint.c:19: error: unknown field 'colour'; did you mean 'color'
+ 19 | return p->colour;
+ | ^~~~~~
+ | color
+
+ along with the equivalent in SARIF, and a generated patch (on stderr) to
+ make the change. */
+
+#include "libdiagnostics.h"
+#include "test-helpers.h"
+
+/*
+_________11111111112
+12345678901234567890
+ return p->colour;
+*/
+const int line_num = __LINE__ - 2;
+
+int
+main ()
+{
+ diagnostic_manager *diag_mgr = diagnostic_manager_new ();
+
+ diagnostic_manager_add_text_sink (diag_mgr, stderr,
+ DIAGNOSTIC_COLORIZE_IF_TTY);
+ diagnostic_manager_add_sarif_sink (diag_mgr, stderr,
+ DIAGNOSTIC_SARIF_VERSION_2_1_0);
+
+ const diagnostic_file *file = diagnostic_manager_new_file (diag_mgr, __FILE__, "c");
+ const diagnostic_physical_location *loc_token
+ = make_range (diag_mgr, file, line_num, 13, 18);
+
+ diagnostic *d = diagnostic_begin (diag_mgr,
+ DIAGNOSTIC_LEVEL_ERROR);
+ diagnostic_set_location (d, loc_token);
+
+ diagnostic_add_fix_it_hint_replace (d, loc_token, "color");
+
+ diagnostic_finish (d, "unknown field %qs; did you mean %qs", "colour", "color");
+
+ diagnostic_manager_write_patch (diag_mgr, stderr);
+
+ diagnostic_manager_release (diag_mgr);
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,29 @@
+/* Common utility code shared between test cases. */
+
+#ifndef TEST_HELPERS_H
+#define TEST_HELPERS_H
+
+const diagnostic_physical_location *
+make_range (diagnostic_manager *diag_mgr,
+ const diagnostic_file *file,
+ diagnostic_line_num_t line_num,
+ diagnostic_column_num_t start_column,
+ diagnostic_column_num_t end_column)
+{
+ const diagnostic_physical_location *loc_start
+ = diagnostic_manager_new_location_from_file_line_column (diag_mgr,
+ file,
+ line_num,
+ start_column);
+ const diagnostic_physical_location *loc_end
+ = diagnostic_manager_new_location_from_file_line_column (diag_mgr,
+ file,
+ line_num,
+ end_column);
+ return diagnostic_manager_new_location_from_range (diag_mgr,
+ loc_start,
+ loc_start,
+ loc_end);
+}
+
+#endif /* #ifndef TEST_HELPERS_H */
new file mode 100644
@@ -0,0 +1,52 @@
+/* Example of multiple locations, with labelling of ranges.
+
+ Intended output is similar to:
+
+PATH/test-labelled-ranges.c:9: error: mismatching types: 'int' and 'const char *'
+ 19 | 42 + "foo"
+ | ~~ ^ ~~~~~
+ | | |
+ | int const char *
+
+ along with the equivalent in SARIF. */
+
+#include "libdiagnostics.h"
+#include "test-helpers.h"
+
+/*
+_________11111111112
+12345678901234567890
+ 42 + "foo"
+*/
+const int line_num = __LINE__ - 2;
+
+int
+main ()
+{
+ diagnostic_manager *diag_mgr = diagnostic_manager_new ();
+
+ diagnostic_manager_add_text_sink (diag_mgr, stderr,
+ DIAGNOSTIC_COLORIZE_IF_TTY);
+ diagnostic_manager_add_sarif_sink (diag_mgr, stderr,
+ DIAGNOSTIC_SARIF_VERSION_2_1_0);
+
+ const diagnostic_file *file = diagnostic_manager_new_file (diag_mgr, __FILE__, "c");
+ const diagnostic_physical_location *loc_operator
+ = diagnostic_manager_new_location_from_file_line_column (diag_mgr, file, line_num, 6);
+
+
+ diagnostic *d = diagnostic_begin (diag_mgr,
+ DIAGNOSTIC_LEVEL_ERROR);
+ diagnostic_set_location (d, loc_operator);
+ diagnostic_add_location_with_label (d,
+ make_range (diag_mgr, file, line_num, 3, 4),
+ "int");
+ diagnostic_add_location_with_label (d,
+ make_range (diag_mgr, file, line_num, 8, 12),
+ "const char *");
+
+ diagnostic_finish (d, "mismatching types: %qs and %qs", "int", "const char *");
+
+ diagnostic_manager_release (diag_mgr);
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,60 @@
+/* Example of using a logical location.
+
+ Intended output is similar to:
+
+In function 'test_qualified_name':
+PATH/test-error-with-note.c:6: error: can't find 'foo'
+ 6 | PRINT "hello world!";
+ | ^~~~~~~~~~~~
+
+ along with the equivalent in SARIF. */
+
+#include "libdiagnostics.h"
+
+/* Placeholder source:
+_________111111111122
+123456789012345678901
+PRINT "hello world!";
+*/
+const int line_num = __LINE__ - 2;
+
+int
+main ()
+{
+ diagnostic_manager *diag_mgr = diagnostic_manager_new ();
+
+ diagnostic_manager_add_text_sink (diag_mgr, stderr,
+ DIAGNOSTIC_COLORIZE_IF_TTY);
+ diagnostic_manager_add_sarif_sink (diag_mgr, stderr,
+ DIAGNOSTIC_SARIF_VERSION_2_1_0);
+
+ const diagnostic_file *file = diagnostic_manager_new_file (diag_mgr, __FILE__, "c");
+ const diagnostic_physical_location *loc_start
+ = diagnostic_manager_new_location_from_file_line_column (diag_mgr, file, line_num, 8);
+ const diagnostic_physical_location *loc_end
+ = diagnostic_manager_new_location_from_file_line_column (diag_mgr, file, line_num, 19);
+ const diagnostic_physical_location *loc_range
+ = diagnostic_manager_new_location_from_range (diag_mgr,
+ loc_start,
+ loc_start,
+ loc_end);
+
+ diagnostic *d = diagnostic_begin (diag_mgr,
+ DIAGNOSTIC_LEVEL_ERROR);
+ diagnostic_set_location (d, loc_range);
+
+ const diagnostic_logical_location *logical_loc
+ = diagnostic_manager_new_logical_location (diag_mgr,
+ DIAGNOSTIC_LOGICAL_LOCATION_KIND_FUNCTION,
+ NULL, /* parent */
+ "test_short_name",
+ "test_qualified_name",
+ "test_decorated_name");
+
+ diagnostic_set_logical_location (d, logical_loc);
+
+ diagnostic_finish (d, "can't find %qs", "foo");
+
+ diagnostic_manager_release (diag_mgr);
+ return 0;
+};
new file mode 100644
@@ -0,0 +1,54 @@
+/* Example of setting a CWE and adding extra metadata.
+
+ Intended output is similar to:
+
+PATH/test-metadata.c:21: warning: never use 'gets' [CWE-242] [STR34-C]
+ 21 | gets (buf);
+ | ^~~~~~~~~~
+
+ where the metadata tags are linkified in a sufficiently capable terminal,
+ along with the equivalent in SARIF. */
+
+#include "libdiagnostics.h"
+#include "test-helpers.h"
+
+/* Placeholder source:
+_________11111111112
+12345678901234567890
+void test_cwe (void)
+{
+ char buf[1024];
+ gets (buf);
+}
+*/
+const int line_num = __LINE__ - 3;
+
+int
+main ()
+{
+ diagnostic_manager *diag_mgr = diagnostic_manager_new ();
+
+ diagnostic_manager_set_tool_name (diag_mgr, "FooChecker");
+ diagnostic_manager_set_full_name (diag_mgr, "FooChecker 0.1 (en_US)");
+ diagnostic_manager_set_version_string (diag_mgr, "0.1");
+ diagnostic_manager_set_version_url (diag_mgr, "https://www.example.com/0.1/");
+
+ diagnostic_manager_add_text_sink (diag_mgr, stderr,
+ DIAGNOSTIC_COLORIZE_IF_TTY);
+ diagnostic_manager_add_sarif_sink (diag_mgr, stderr,
+ DIAGNOSTIC_SARIF_VERSION_2_1_0);
+
+ const diagnostic_file *file = diagnostic_manager_new_file (diag_mgr, __FILE__, "c");
+ const diagnostic_physical_location *loc_token
+ = make_range (diag_mgr, file, line_num, 3, 12);
+ diagnostic *d = diagnostic_begin (diag_mgr,
+ DIAGNOSTIC_LEVEL_WARNING);
+ diagnostic_set_location (d, loc_token);
+ diagnostic_set_cwe (d, 242); /* CWE-242: Use of Inherently Dangerous Function. */
+ diagnostic_add_rule (d, "STR34-C", "https://example.com/");
+
+ diagnostic_finish (d, "never use %qs", "gets");
+
+ diagnostic_manager_release (diag_mgr);
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,61 @@
+/* Example of a warning with multiple locations in various source lines,
+ with an insertion fix-it hint.
+
+ Intended output is similar to:
+
+/PATH/test-multiple-lines.c:17: warning: missing comma
+ 16 | const char *strs[3] = {"foo",
+ | ~~~~~
+ 17 | "bar"
+ | ~~~~~^
+ 18 | "baz"};
+ | ~~~~~
+
+ along with the equivalent in SARIF. */
+
+#include "libdiagnostics.h"
+#include "test-helpers.h"
+
+/* Placeholder source (missing comma after "bar"):
+_________11111111112222222222
+12345678901234567890123456789
+const char *strs[3] = {"foo",
+ "bar"
+ "baz"};
+*/
+const int foo_line_num = __LINE__ - 4;
+
+int
+main ()
+{
+ diagnostic_manager *diag_mgr = diagnostic_manager_new ();
+
+ diagnostic_manager_add_text_sink (diag_mgr, stderr,
+ DIAGNOSTIC_COLORIZE_IF_TTY);
+ diagnostic_manager_add_sarif_sink (diag_mgr, stderr,
+ DIAGNOSTIC_SARIF_VERSION_2_1_0);
+
+ const diagnostic_file *file = diagnostic_manager_new_file (diag_mgr, __FILE__, "c");
+ const diagnostic_physical_location *loc_comma
+ = diagnostic_manager_new_location_from_file_line_column (diag_mgr, file, foo_line_num + 1, 29);
+ const diagnostic_physical_location *loc_foo
+ = make_range (diag_mgr, file, foo_line_num, 24, 28);
+ const diagnostic_physical_location *loc_bar
+ = make_range (diag_mgr, file, foo_line_num + 1, 24, 28);
+ const diagnostic_physical_location *loc_baz
+ = make_range (diag_mgr, file, foo_line_num + 2, 24, 28);
+
+ diagnostic *d = diagnostic_begin (diag_mgr,
+ DIAGNOSTIC_LEVEL_WARNING);
+ diagnostic_set_location (d, loc_comma);
+ diagnostic_add_location (d, loc_foo);
+ diagnostic_add_location (d, loc_bar);
+ diagnostic_add_location (d, loc_baz);
+
+ diagnostic_add_fix_it_hint_insert_after (d, loc_bar, ",");
+
+ diagnostic_finish (d, "missing comma");
+
+ diagnostic_manager_release (diag_mgr);
+ return 0;
+};
new file mode 100644
@@ -0,0 +1,41 @@
+/* Example of emitting an error without a column number.
+
+ Intended output is similar to:
+
+PATH/test-error-with-note.c:6: error: can't find 'foo'
+ 6 | PRINT "hello world!";
+
+ along with the equivalent in SARIF. */
+
+#include "libdiagnostics.h"
+
+/*
+_________111111111122
+123456789012345678901
+PRINT "hello world!";
+*/
+const int line_num = __LINE__ - 2;
+
+int
+main ()
+{
+ diagnostic_manager *diag_mgr = diagnostic_manager_new ();
+
+ diagnostic_manager_add_text_sink (diag_mgr, stderr,
+ DIAGNOSTIC_COLORIZE_IF_TTY);
+ diagnostic_manager_add_sarif_sink (diag_mgr, stderr,
+ DIAGNOSTIC_SARIF_VERSION_2_1_0);
+
+ const diagnostic_file *file = diagnostic_manager_new_file (diag_mgr, __FILE__, "c");
+ const diagnostic_physical_location *loc
+ = diagnostic_manager_new_location_from_file_and_line (diag_mgr, file, line_num);
+
+ diagnostic *d = diagnostic_begin (diag_mgr,
+ DIAGNOSTIC_LEVEL_ERROR);
+ diagnostic_set_location (d, loc);
+
+ diagnostic_finish (d, "can't find %qs", "foo");
+
+ diagnostic_manager_release (diag_mgr);
+ return 0;
+};
new file mode 100644
@@ -0,0 +1,52 @@
+/* Example of a grouped error and note, with a fix-it hint on the note.
+
+ Intended output is similar to:
+
+/PATH/test-note-with-fix-it-hint.c:19: error: unknown field 'colour'
+ 19 | return p->colour;
+ | ^~~~~~
+/PATH/test-note-with-fix-it-hint.c:19: note: did you mean 'color'
+ 19 | return p->colour;
+ | ^~~~~~
+ | color
+
+ along with the equivalent in SARIF. */
+
+#include "libdiagnostics.h"
+#include "test-helpers.h"
+
+/* Placeholder source:
+_________11111111112
+12345678901234567890
+ return p->colour;
+*/
+const int line_num = __LINE__ - 2;
+
+int
+main ()
+{
+ diagnostic_manager *diag_mgr = diagnostic_manager_new ();
+
+ diagnostic_manager_add_text_sink (diag_mgr, stderr, DIAGNOSTIC_COLORIZE_IF_TTY);
+ diagnostic_manager_add_sarif_sink (diag_mgr, stderr, DIAGNOSTIC_SARIF_VERSION_2_1_0);
+
+ const diagnostic_file *file = diagnostic_manager_new_file (diag_mgr, __FILE__, "c");
+ const diagnostic_physical_location *loc_token
+ = make_range (diag_mgr, file, line_num, 13, 18);
+
+ diagnostic_manager_begin_group (diag_mgr);
+
+ diagnostic *err = diagnostic_begin (diag_mgr, DIAGNOSTIC_LEVEL_ERROR);
+ diagnostic_set_location (err, loc_token);
+ diagnostic_finish (err, "unknown field %qs", "colour");
+
+ diagnostic *n = diagnostic_begin (diag_mgr, DIAGNOSTIC_LEVEL_NOTE);
+ diagnostic_set_location (n, loc_token);
+ diagnostic_add_fix_it_hint_replace (n, loc_token, "color");
+ diagnostic_finish (n, "did you mean %qs", "color");
+
+ diagnostic_manager_end_group (diag_mgr);
+
+ diagnostic_manager_release (diag_mgr);
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,46 @@
+/* Example of controlling options for text sinks. */
+
+#include "libdiagnostics.h"
+
+/*
+_________111111111122
+123456789012345678901
+PRINT "hello world!";
+*/
+const int line_num = __LINE__ - 2;
+
+int
+main ()
+{
+ diagnostic_manager *diag_mgr = diagnostic_manager_new ();
+
+ diagnostic_text_sink *sink_1
+ = diagnostic_manager_add_text_sink (diag_mgr, stderr,
+ DIAGNOSTIC_COLORIZE_IF_TTY);
+ diagnostic_text_sink_set_source_printing_enabled (sink_1, 0);
+
+ diagnostic_text_sink *sink_2
+ = diagnostic_manager_add_text_sink (diag_mgr, stderr,
+ DIAGNOSTIC_COLORIZE_IF_TTY);
+ diagnostic_text_sink_set_labelled_source_colorization_enabled (sink_2, 0);
+
+ const diagnostic_file *file = diagnostic_manager_new_file (diag_mgr, __FILE__, "c");
+ const diagnostic_physical_location *loc_start
+ = diagnostic_manager_new_location_from_file_line_column (diag_mgr, file, line_num, 8);
+ const diagnostic_physical_location *loc_end
+ = diagnostic_manager_new_location_from_file_line_column (diag_mgr, file, line_num, 19);
+ const diagnostic_physical_location *loc_range
+ = diagnostic_manager_new_location_from_range (diag_mgr,
+ loc_start,
+ loc_start,
+ loc_end);
+
+ diagnostic *d = diagnostic_begin (diag_mgr,
+ DIAGNOSTIC_LEVEL_ERROR);
+ diagnostic_set_location (d, loc_range);
+
+ diagnostic_finish (d, "can't find %qs", "foo");
+
+ diagnostic_manager_release (diag_mgr);
+ return 0;
+};
new file mode 100644
@@ -0,0 +1,52 @@
+/* Example of emitting a warning.
+
+ Intended output is similar to:
+
+/PATH/test-warning.c:15: warning: this is a warning
+ 15 | PRINT "hello world!";
+ | ^~~~~~~~~~~~
+
+ along with the equivalent in SARIF. */
+
+#include "libdiagnostics.h"
+
+/*
+_________111111111122
+123456789012345678901
+PRINT "hello world!";
+*/
+const int line_num = __LINE__ - 2;
+
+int
+main ()
+{
+ diagnostic_manager *diag_mgr = diagnostic_manager_new ();
+
+ diagnostic_manager_add_text_sink (diag_mgr, stderr,
+ DIAGNOSTIC_COLORIZE_IF_TTY);
+ diagnostic_manager_add_sarif_sink (diag_mgr, stderr,
+ DIAGNOSTIC_SARIF_VERSION_2_1_0);
+
+ const diagnostic_file *file = diagnostic_manager_new_file (diag_mgr,
+ __FILE__,
+ "c");
+
+ const diagnostic_physical_location *loc_start
+ = diagnostic_manager_new_location_from_file_line_column (diag_mgr, file, line_num, 8);
+ const diagnostic_physical_location *loc_end
+ = diagnostic_manager_new_location_from_file_line_column (diag_mgr, file, line_num, 19);
+ const diagnostic_physical_location *loc_range
+ = diagnostic_manager_new_location_from_range (diag_mgr,
+ loc_start,
+ loc_start,
+ loc_end);
+
+ diagnostic *d = diagnostic_begin (diag_mgr,
+ DIAGNOSTIC_LEVEL_WARNING);
+ diagnostic_set_location (d, loc_range);
+
+ diagnostic_finish (d, "this is a warning");
+
+ diagnostic_manager_release (diag_mgr);
+ return 0;
+};
new file mode 100644
@@ -0,0 +1,46 @@
+/* Example of writing diagnostics as SARIF to a file. */
+
+#include "libdiagnostics.h"
+
+/*
+_________111111111122
+123456789012345678901
+PRINT "hello world!";
+*/
+const int line_num = __LINE__ - 2;
+
+int
+main ()
+{
+ FILE *outfile = fopen ("test.txt", "w");
+ if (!outfile)
+ return -1;
+
+ diagnostic_manager *diag_mgr = diagnostic_manager_new ();
+
+ diagnostic_manager_add_sarif_sink (diag_mgr, outfile,
+ DIAGNOSTIC_SARIF_VERSION_2_1_0);
+
+ const diagnostic_file *file = diagnostic_manager_new_file (diag_mgr, __FILE__, "c");
+ const diagnostic_physical_location *loc_start
+ = diagnostic_manager_new_location_from_file_line_column (diag_mgr, file, line_num, 8);
+ const diagnostic_physical_location *loc_end
+ = diagnostic_manager_new_location_from_file_line_column (diag_mgr, file, line_num, 19);
+ const diagnostic_physical_location *loc_range
+ = diagnostic_manager_new_location_from_range (diag_mgr,
+ loc_start,
+ loc_start,
+ loc_end);
+
+ diagnostic *d = diagnostic_begin (diag_mgr,
+ DIAGNOSTIC_LEVEL_ERROR);
+ diagnostic_set_location (d, loc_range);
+
+ diagnostic_finish (d, "can't find %qs", "foo");
+
+ diagnostic_manager_release (diag_mgr);
+
+ fclose (outfile);
+
+ return 0;
+};
new file mode 100644
@@ -0,0 +1,47 @@
+/* Example of writing diagnostics in text form, but to a file,
+ rather than stderr. */
+
+#include "libdiagnostics.h"
+
+/*
+_________111111111122
+123456789012345678901
+PRINT "hello world!";
+*/
+const int line_num = __LINE__ - 2;
+
+int
+main ()
+{
+ FILE *outfile = fopen ("test.txt", "w");
+ if (!outfile)
+ return -1;
+
+ diagnostic_manager *diag_mgr = diagnostic_manager_new ();
+
+ diagnostic_manager_add_text_sink (diag_mgr, outfile,
+ DIAGNOSTIC_COLORIZE_NO);
+
+ const diagnostic_file *file = diagnostic_manager_new_file (diag_mgr, __FILE__, "c");
+ const diagnostic_physical_location *loc_start
+ = diagnostic_manager_new_location_from_file_line_column (diag_mgr, file, line_num, 8);
+ const diagnostic_physical_location *loc_end
+ = diagnostic_manager_new_location_from_file_line_column (diag_mgr, file, line_num, 19);
+ const diagnostic_physical_location *loc_range
+ = diagnostic_manager_new_location_from_range (diag_mgr,
+ loc_start,
+ loc_start,
+ loc_end);
+
+ diagnostic *d = diagnostic_begin (diag_mgr,
+ DIAGNOSTIC_LEVEL_ERROR);
+ diagnostic_set_location (d, loc_range);
+
+ diagnostic_finish (d, "can't find %qs", "foo");
+
+ diagnostic_manager_release (diag_mgr);
+
+ fclose (outfile);
+
+ return 0;
+};