Tutorial part 4: adding notes

Let’s further extend the previous example to add a “note” to it.

We want to generate output like this:

test-with-note.c:17:11: error: can't find 'foo.h'
17 | #include <foo.h>
   |           ^~~~~
test-with-note.c:17:11: note: have you looked behind the couch?

The “error” and “note” are both instances of diagnostic. We want to let libgdiagnostics know that they are grouped together. The way to do this is to use diagnostic_manager_begin_group() and diagnostic_manager_end_group() around the “finish” calls to the diagnostics.

  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.h");

  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);

On compiling and running the program, we should get the desired output:

test-with-note.c:17:11: error: can't find 'foo.h'
17 | #include <foo.h>
   |           ^~~~~
test-with-note.c:17:11: note: have you looked behind the couch?

The grouping doesn’t affect text output sinks, but a SARIF sink will group the note within the error (via the relatedLocations property of result objects; see SARIF v2.1.0 §3.27.22).

In the above, the note had the same physical location as the error (loc_range). This can be useful for splitting up a message into two parts to make localization easier, but they could have different locations, such as in:

test.xml:10:2: error: 'foo' is not valid here
test.xml:5:1: note: within element 'bar'

where each diagnostic had its own diagnostic_physical_location.

In the next tutorial we’ll look at issuing warnings, rather than errors.