diagnostics: SARIF output: fix "executionSuccessful" §3.20.14 [PR116177]

Previously the invocation's "executionSuccessful" property (§3.20.14)
was only false if there was an ICE.

Update it so that it will also be false if we will exit with a non-zero
exit code (due to errors, Werror, and "sorry").

gcc/ChangeLog:
	PR other/116177
	* diagnostic-format-sarif.cc (sarif_invocation::prepare_to_flush):
	If the diagnostics would lead to us exiting with a failure code,
	then emit "executionSuccessful": False (SARIF v2.1.0 section
	§3.20.14).
	* diagnostic.cc (diagnostic_context::execution_failed_p): New.
	* diagnostic.h (diagnostic_context::execution_failed_p): New decl.
	* toplev.cc (toplev::main): Use it for determining returned value.

gcc/testsuite/ChangeLog:
	PR other/116177
	* gcc.dg/sarif-output/include-chain-2.c: Remove pruning of
	"exit status is 1", as we expect this to exit with 0.
	* gcc.dg/sarif-output/no-diagnostics.c: New test.
	* gcc.dg/sarif-output/test-include-chain-1.py
	(test_execution_unsuccessful): Add.
	* gcc.dg/sarif-output/test-include-chain-2.py
	(test_execution_successful): Add.
	* gcc.dg/sarif-output/test-missing-semicolon.py
	(test_execution_unsuccessful): Add.
	* gcc.dg/sarif-output/test-no-diagnostics.py: New test.
	* gcc.dg/sarif-output/test-werror.py: New test.
	* gcc.dg/sarif-output/werror.c: New test.

Signed-off-by: David Malcolm <dmalcolm@redhat.com>
This commit is contained in:
David Malcolm 2024-08-06 18:24:45 -04:00
parent a50916a6c0
commit 77f36e8016
12 changed files with 152 additions and 6 deletions

View file

@ -811,6 +811,8 @@ void
sarif_invocation::prepare_to_flush (diagnostic_context &context)
{
/* "executionSuccessful" property (SARIF v2.1.0 section 3.20.14). */
if (context.execution_failed_p ())
m_success = false;
set_bool ("executionSuccessful", m_success);
/* "toolExecutionNotifications" property (SARIF v2.1.0 section 3.20.21). */

View file

@ -399,6 +399,19 @@ diagnostic_context::finish ()
m_original_argv = nullptr;
}
/* Return true if sufficiently severe diagnostics have been seen that
we ought to exit with a non-zero exit code. */
bool
diagnostic_context::execution_failed_p () const
{
/* Equivalent to (seen_error () || werrorcount), but on
this context, rather than global_dc. */
return (m_diagnostic_count [DK_ERROR]
|| m_diagnostic_count [DK_SORRY]
|| m_diagnostic_count [DK_WERROR]);
}
void
diagnostic_context::set_output_format (diagnostic_output_format *output_format)
{

View file

@ -392,6 +392,8 @@ public:
void finish ();
bool execution_failed_p () const;
void set_original_argv (unique_argv original_argv);
const char * const *get_original_argv ()
{

View file

@ -27,11 +27,6 @@ PATH/include-chain-2.h:6:3: warning: double-'free' of 'ptr' [CWE-415] [-Wanalyze
#include "include-chain-2.h"
/* We expect a failing compile due to the errors, but the use of
-fdiagnostics-format=sarif-file means there should be no output to stderr.
DejaGnu injects this message; ignore it:
{ dg-prune-output "exit status is 1" } */
/* Verify that some JSON was written to a file with the expected name:
{ dg-final { verify-sarif-file } } */

View file

@ -0,0 +1,13 @@
/* { dg-do compile } */
/* { dg-options "-fdiagnostics-format=sarif-file" } */
/* Verify our SARIF output for a translation unit with no diagnostics. */
int nonempty;
/* Verify that some JSON was written to a file with the expected name:
{ dg-final { verify-sarif-file } } */
/* Use a Python script to verify various properties about the generated
.sarif file:
{ dg-final { run-sarif-pytest no-diagnostics.c "test-no-diagnostics.py" } } */

View file

@ -13,6 +13,17 @@ def test_basics(sarif):
version = sarif['version']
assert version == "2.1.0"
def test_execution_unsuccessful(sarif):
runs = sarif['runs']
run = runs[0]
invocations = run['invocations']
assert len(invocations) == 1
invocation = invocations[0]
# We expect the errors to make executionSuccessful be false
assert invocation['executionSuccessful'] == False
def test_location_relationships(sarif):
runs = sarif['runs']
run = runs[0]

View file

@ -31,6 +31,17 @@ def test_basics(sarif):
version = sarif['version']
assert version == "2.1.0"
def test_execution_successful(sarif):
runs = sarif['runs']
run = runs[0]
invocations = run['invocations']
assert len(invocations) == 1
invocation = invocations[0]
# We expect a mere 'warning' to allow executionSuccessful be true
assert invocation['executionSuccessful'] == True
def test_result(sarif):
runs = sarif['runs']
run = runs[0]

View file

@ -13,6 +13,17 @@ def test_basics(sarif):
version = sarif['version']
assert version == "2.1.0"
def test_execution_unsuccessful(sarif):
runs = sarif['runs']
run = runs[0]
invocations = run['invocations']
assert len(invocations) == 1
invocation = invocations[0]
# We expect the 'error' to make executionSuccessful be false
assert invocation['executionSuccessful'] == False
def test_location_relationships(sarif):
runs = sarif['runs']
run = runs[0]

View file

@ -0,0 +1,31 @@
from sarif import *
import pytest
@pytest.fixture(scope='function', autouse=True)
def sarif():
return sarif_from_env()
def test_basics(sarif):
schema = sarif['$schema']
assert schema == "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json"
version = sarif['version']
assert version == "2.1.0"
def test_execution_successful(sarif):
runs = sarif['runs']
run = runs[0]
invocations = run['invocations']
assert len(invocations) == 1
invocation = invocations[0]
assert invocation['executionSuccessful'] == True
assert invocation['toolExecutionNotifications'] == []
def test_empty_results(sarif):
runs = sarif['runs']
run = runs[0]
results = run['results']
assert len(results) == 0

View file

@ -0,0 +1,39 @@
from sarif import *
import pytest
@pytest.fixture(scope='function', autouse=True)
def sarif():
return sarif_from_env()
def test_basics(sarif):
schema = sarif['$schema']
assert schema == "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json"
version = sarif['version']
assert version == "2.1.0"
def test_execution_unsuccessful(sarif):
runs = sarif['runs']
run = runs[0]
invocations = run['invocations']
assert len(invocations) == 1
invocation = invocations[0]
assert '-Werror=unused-variable' in invocation['arguments']
# We expect the 'Werror' to make executionSuccessful be false
assert invocation['executionSuccessful'] == False
def test_result(sarif):
runs = sarif['runs']
run = runs[0]
results = run['results']
assert len(results) == 1
result = results[0]
assert result['ruleId'] == '-Werror=unused-variable'
assert result['level'] == 'error'
assert result['message']['text'] == "'ununsed' defined but not used"

View file

@ -0,0 +1,18 @@
/* { dg-do compile } */
/* { dg-options "-Werror=unused-variable -fdiagnostics-format=sarif-file" } */
/* Verify our SARIF output for a translation unit with -Werror. */
static int ununsed;
/* We expect a failing compile due to the Werror, but the use of
-fdiagnostics-format=sarif-file means there should be no output to stderr.
DejaGnu injects this message; ignore it:
{ dg-prune-output "exit status is 1" } */
/* Verify that some JSON was written to a file with the expected name:
{ dg-final { verify-sarif-file } } */
/* Use a Python script to verify various properties about the generated
.sarif file:
{ dg-final { run-sarif-pytest werror.c "test-werror.py" } } */

View file

@ -2355,7 +2355,7 @@ toplev::main (int argc, char **argv)
after_memory_report = true;
if (seen_error () || werrorcount)
if (global_dc->execution_failed_p ())
return (FATAL_EXIT_CODE);
return (SUCCESS_EXIT_CODE);