tool_diagnostics

This tool provides the shared tool_diagnostics_protocol protocol and the tool_diagnostics_common category used by developer tools such as dead_code_scanner, lgtdoc, lgtunit, and linter_reporter to expose machine-readable diagnostics.

The protocol is designed so that producer tools can keep their own internal semantics while still providing a common interface for querying diagnostics directly or for generating SARIF reports using the sarif tool.

API documentation

This tool API documentation is available at:

../../apis/library_index.html#tool_diagnostics_protocol

Loading

Load the protocol and common category definitions using:

| ?- logtalk_load(tool_diagnostics(loader)).
...

Protocol overview

The protocol defines predicates for reporting:

  • tool metadata using diagnostics_tool/5

  • supported target patterns using diagnostic_target/1

  • rule descriptors using diagnostic_rule/5 and diagnostic_rules/1

  • diagnostics using diagnostic/2-3 and diagnostics/2-3

  • summaries using diagnostics_summary/2-3

  • preflight issues using diagnostics_preflight/2-3

Common target terms include all, file(File), directory(Directory), rdirectory(Directory), library(Library), rlibrary(Library), entity(Entity), and tests(Object).

Predicates taking an Options argument must accept the common option explanations(Boolean). Tools may use it to include explanation(Text) properties when available, but implementations that do not provide additional explanation text must still accept the option as a no-op.

Term conventions

Tool metadata uses terms of the form:

diagnostics_tool(Id, Name, Version, InformationURI, Properties)

The Id and Name arguments identify the tool. The Version argument should be derived reflectively from the implementing object info/1 metadata using object_property/2 instead of being hardcoded. The InformationURI argument is a stable tool home or documentation URI and is exported by the sarif tool as the SARIF tool.driver.informationUri value.

The Properties list is intended for exporter and post-processing hints. The current sarif tool interprets the following entries:

  • guid(Guid) sets the SARIF tool.driver.guid value when present.

  • fingerprint_algorithm(Algorithm) sets the exported run fingerprintAlgorithm property and selects the canonical result fingerprint key. The current implementation distinguishes canonical_finding_v1 from the default warning-oriented path and computes result identities from normalized relative locations instead of raw absolute file paths.

  • automation_id(target) requests that the SARIF run.automationDetails.id value be derived from the queried target term, allowing different targets of the same tool to produce distinct run identities.

  • automation_id(tool) denotes a tool-scoped automation identifier. In the current sarif implementation this is redundant because omitting automation_id(target) already falls back to the tool identifier.

  • include_invocations(true) requests a SARIF invocations section, including toolExecutionNotifications when preflight issues exist.

  • include_git_metadata(true) requests SARIF gitBranch and gitCommitHash run properties when a stable Git context can be inferred. When this succeeds, the sarif tool also normalizes artifact locations and fingerprint inputs relative to the repository root. The gitBranch value is descriptive metadata; the gitCommitHash value provides the stable revision identity used to disambiguate repository-relative paths.

  • include_version_control_provenance(true) requests SARIF versionControlProvenance data when repository details can be inferred from diagnostic file paths.

  • count_key(Key) selects the property name used for the exported count, e.g. diagnosticsCount or totalWarnings.

When include_git_metadata(true) is not present or a stable Git context cannot be inferred, the sarif tool falls back to application-root-relative artifact locations and fingerprint inputs instead.

Rule descriptors use terms of the form:

diagnostic_rule(RuleId, ShortDescription, FullDescription, DefaultSeverity, Properties)

The diagnostic_rules/1 predicate should return these descriptors in a stable order. Rule descriptor properties may contain terms such as guid(Guid), help(Text), help_uri(URI), tags(Tags), and precision(Precision).

Diagnostics use terms of the form:

diagnostic(RuleId, Severity, Confidence, Message, Context, File, Lines, Properties)

The Context argument is represented using the term context(Kind, Identifier) where Kind is a tool-defined atom such as file, object, category, protocol, or test_set. For file-scoped diagnostics, Identifier is the source file path when available and the empty atom otherwise. Diagnostics originating in an included file may still use an entity context when the include/1 directive appears inside that entity; otherwise they are file-scoped.

The File argument is a source file path or the empty atom when unavailable. The Lines argument uses the Start-End notation. The value 0-0 means that no precise line information is available.

Supported severity values are error, warning, and note. Supported confidence values are high, medium, low, and not_applicable.

The Properties argument should include stable structured metadata such as raw_term(Term), explanation(Text), flag(Flag), directive(Directive), indicator(Indicator), key(Key), test(Test), option(Option), and any other tool-specific facts useful for post-processing.

Preflight issues use terms of the form:

preflight_issue(Id, Severity, Message, Context, File, Lines, Properties)

Preflight issues describe prerequisites or analysis quality issues instead of findings.

Summaries use terms of the form:

diagnostics_summary(Target, TotalContexts, TotalDiagnostics, Breakdown, ContextSummaries)

The Breakdown argument uses a diagnostic_breakdown(RuleCounts, SeverityCounts, ConfidenceCounts) term and ContextSummaries is a list of context_summary(Context, DiagnosticsCount, Breakdown) terms.

Rule counts use rule_count(RuleId, Count) terms, severity counts use severity_count(Severity, Count) terms, and confidence counts use confidence_count(Confidence, Count) terms.

Usage

Tools implementing this protocol can be queried directly for diagnostics after compiling code that results in the production of diagnostics. For example:

| ?- logtalk_load(dead_code_scanner(loader)).
...

| ?- logtalk_load(my_library(loader)).
...

| ?- dead_code_scanner::diagnostics(library(my_library), Diagnostics).
...

To serialize diagnostics as SARIF, load the standalone sarif tool and generate a report from a diagnostics producer:

| ?- logtalk_load(sarif(loader)).
...

| ?- sarif::generate(dead_code_scanner, entity(my_object), file('./report.sarif'), []).
true.

To generate an explicit aggregate SARIF report with multiple diagnostics producers, pass a list of tool_spec(Tool, Target, Options) terms:

| ?- sarif::generate([
|        tool_spec(linter_reporter, all, []),
|        tool_spec(dead_code_scanner, entity(my_object), [])
|    ], file('./aggregate.sarif')).
true.