Diagnostics

APIs that support issuing diagnostics.

Diagnostic Class

The slang::Diagnostic class represents a diagnostic that has been created in response to some issue with the user's source code. It contains a slang::DiagCode that indicates what that issue is, a collection of arguments that may be used to format a human-friendly message describing the issue, and some other metadata like the location where the issue occurred. The Diagnostic class provides several operator<< overloads that can be used to add arguments and metadata when constructing a new diagnostic.

There is a slang::Diagnostics class, which derives from slang::SmallVectorSized and adds a few helper methods for creating diagnostics. An example of constructing a new diagnostic:

Diagnostics diags;
Diagnostic& diag = diags.add(diag::SomeDiagCode, location);
diag << arg1 << arg2;

The slang::diag namespace contains all of the DiagCodes that are generated automatically as part of the build (sourced from the diagnostics.txt file). Each DiagCode is a combination of a slang::DiagSubsystem that indicates the general system that creates that kind of diagnostic and a simple index within that subsystem. It's also possible for a consumer of the slang library to create its own DiagCode and issue them via the diagnostic system.

Diagnostic Engine

The slang::Diagnostics class is just a simple collection of diagnostics. A richer set of functionality for formatting, filtering, and controlling those diagnostics is provided by the slang::DiagnosticEngine class. The engine provides methods for things like setting limits on the number of diagnostics to issue, options that can hide all or some subset of warnings, and the ability to remap the default severity of a given diagnostic code.

Each Diagnostic that is issued to a DiagnosticEngine is formatted and, assuming it's not supressed, forwarded to all registered slang::DiagnosticClient instances. Clients are registered with the engine via slang::DiagnosticEngine::addClient. It's the client's job to actually do something with the diagnostic; for example, it may write the text to an internal buffer, or dump the diagnostic to a JSON file, or send it over a pipe to another process.

You can make a DiagnosticClient to do whatever you want, but the built in slang::TextDiagnosticClient formats each diagnostic to an internal string buffer that you can then access to get a report. It can also add terminal color codes to the report if you're going to be outputing it to a console.

A basic example of setting up a diagnostic engine along with a text client:

DiagnosticEngine diagEngine(sourceManager);

auto client = std::make_shared<TextDiagnosticClient>();
diagEngine.addClient(client);

for (Diagnostic& diag : diags)
    diagEngine.issue(diag);

std::string report = client->getString();