Physical locations¶
A “physical” source location is a location expressed in terms of a specific file, and line(s) and column(s) (as opposed to a “logical” location, which refers to semantic constructs in a programming language).
Creating location information¶
The diagnostic_manager
manages various objects relating to
locations.
-
type diagnostic_file¶
A
diagnostic_file
is an opaque type describing a particular input file.
-
diagnostic_file *diagnostic_manager_new_file(diagnostic_manager *diag_mgr, const char *name, const char *sarif_source_language)¶
Create a new
diagnostic_file
for filename
. Repeated calls with strings that matchname
will return the same object.Both
diag_mgr
andname
must be non-NULL.If
sarif_source_language
is non-NULL, it specifies asourceLanguage
value for the file for use when writing SARIF (SARIF v2.1.0 §3.24.10). See SARIF v2.1.0 Appendix J for suggested values for various programmming languages.For example, this creates a
diagnostic_file
forfoo.c
and identifies it as C source code:foo_c = diagnostic_manager_new_file (diag_mgr, "foo.c", "c" /* source_language */);
-
void diagnostic_manager_debug_dump_file(diagnostic_manager *diag_mgr, const diagnostic_file *file, FILE *out)¶
Write a representation of
file
toout
, for debugging. Bothdiag_mgr
andout
must be non-NULL. file` may be NULL.For example:
diagnostic_manager_debug_dump_file (diag_mgr, foo_c, stderr);
might lead to this output:
file(name="foo.c", sarif_source_language="c")
-
type diagnostic_line_num_t¶
A diagnostic_line_num_t
is used for representing line numbers
within text files. libgdiagnostics treats the first line of a text file
as line 1.
-
type diagnostic_column_num_t¶
A diagnostic_column_num_t
is used for representing column numbers
within text files. libgdiagnostics treats the first column of a text line
as column 1, not column 0.
Note
Both libgdiagnostics and Emacs number source lines starting at 1, but they have differing conventions for columns.
libgdiagnostics 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 libgdiagnostics 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 libgdiagnostics corresponds to (3, 0)
in Emacs.
-
type diagnostic_physical_location¶
A diagnostic_physical_location
is an opaque type representing a
key into a database of source locations within a diagnostic_manager
.
diagnostic_physical_location
instances 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.
A NULL
value means “unknown”, and can be returned by the
diagnostic_manager
as a fallback when a problem occurs
(e.g. too many locations).
A diagnostic_physical_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.
-
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)¶
Attempt to create a
diagnostic_physical_location
representingFILENAME:LINE_NUM
, with no column information (thus representing the whole of the given line.Both
diag_mgr
andfile
must be non-NULL.
-
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)¶
Attempt to create a
diagnostic_physical_location
forFILENAME:LINE_NUM:COLUMN_NUM
representing a particular point in the source file.Both
diag_mgr
andfile
must be non-NULL.
-
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)¶
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.
diag_mgr
must be non-NULL.
-
void diagnostic_manager_debug_dump_location(const diagnostic_manager *diag_mgr, const diagnostic_physical_location *loc, FILE *out)¶
Write a representation of
loc
toout
, for debugging.Both
diag_mgr
andout
must be non-NULL. loc` may be NULL.TODO: example of output
-
diagnostic_file *diagnostic_physical_location_get_file(const diagnostic_physical_location *physical_loc)¶
Get the
diagnostic_file
associated with a given physical location.
Associating diagnostics with locations¶
A diagnostic
has an optional primary physical location
and zero or more secondary physical locations. For example:
a = (foo && bar)
~~~~~^~~~~~~
This diagnostic has a single diagnostic_physical_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 displayed, 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 displayed, but is perhaps at the”b” of “bar”.
-
void diagnostic_set_location(diagnostic *diag, const diagnostic_physical_location *loc)¶
Set the primary location of
diag
.diag
must be non-NULL;loc
can be NULL.
-
void diagnostic_set_location_with_label(diagnostic *diag, const diagnostic_physical_location *loc, const char *fmt, ...)¶
Set the primary location of
diag
, with a label. The label is formatted as per the rules FIXMEdiag
andfmt
must be non-NULL;loc
can be NULL.See Message formatting for details of how to use
fmt
.TODO: example of use
-
void diagnostic_add_location(diagnostic *diag, const diagnostic_physical_location *loc)¶
Add a secondary location to
diag
.diag
must be non-NULL;loc
can be NULL.
-
void diagnostic_add_location_with_label(diagnostic *diag, const diagnostic_physical_location *loc, const char *text)¶
Add a secondary location to
diag
, with a label. The label is formatted as per the rules FIXMEdiag
andfmt
must be non-NULL;loc
can be NULL.For example,
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, main_file, line_num, 3, 4), "int"); diagnostic_add_location_with_label (d, make_range (diag_mgr, main_file, line_num, 8, 12), "const char *"); diagnostic_finish (d, "mismatching types: %qs and %qs", "int", "const char *");
might give this text output:
test-labelled-ranges.c:9:6: error: mismatching types: 'int' and 'const char *' 19 | 42 + "foo" | ~~ ^ ~~~~~ | | | | int const char *