]> git.ipfire.org Git - thirdparty/gcc.git/commit
diagnostics: SARIF output: capture #include information (PR 107941; §3.34)
authorDavid Malcolm <dmalcolm@redhat.com>
Sat, 27 Jul 2024 00:37:31 +0000 (20:37 -0400)
committerDavid Malcolm <dmalcolm@redhat.com>
Sat, 27 Jul 2024 00:37:31 +0000 (20:37 -0400)
commit4d1f71d49e396cb879d43dc96dc591079af66bbe
tree46fc54a8ce60bf54deeaaba254e4b4c66e699284
parentbe4042092cd69c9dc32d51f095749b1ea76b9bf2
diagnostics: SARIF output: capture #include information (PR 107941; §3.34)

This patch extends our SARIF output to capture relationships between
locations within a result (§3.34).  In particular, this captures
chains of #includes relating to diagnostics and to events within
diagnostic paths.

For example, consider:

include-chain-1.c:

  #include "include-chain-1.h"

include-chain-1.h:

  /* First set of decls, which will be referenced in notes.  */
  #include "include-chain-1-1.h"

  /* Second set of decls, which will trigger the errors.  */
  #include "include-chain-1-2.h"

include-chain-1-1.h:

  int p;
  int q;

include-chain-1-1.h:

  char p;
  char q;

GCC's textual output emits:

  In file included from PATH/include-chain-1.h:5,
                   from PATH/include-chain-1.c:30:
  PATH/include-chain-1-2.h:1:6: error: conflicting types for 'p'; have 'char'
      1 | char p;
        |      ^
  In file included from PATH/include-chain-1.h:2:
  PATH/include-chain-1-1.h:1:5: note: previous declaration of 'p' with type 'int'
      1 | int p;
        |     ^
  PATH/include-chain-1-2.h:2:6: error: conflicting types for 'q'; have 'char'
      2 | char q;
        |      ^
  PATH/include-chain-1-1.h:2:5: note: previous declaration of 'q' with type 'int'
      2 | int q;
        |     ^

With this patch, the SARIF output captures the include information for
the two results, so that e.g. result[0]'s location[0] has:

  "relationships": [{"target": 0,
                     "kinds": ["isIncludedBy"]}],
  "id": 0

and the "note" in relatedLocations[0] has:

  "message": {"text": "previous declaration of 'q' with type 'int'"},
  "relationships": [{"target": 2,
                    "kinds": ["isIncludedBy"]}],
  "id": 2},

where these reference new locations within relatedLocations, such as this for
the "#include "include-chain-1-1.h" line in include-chain-1.h:

  {"physicalLocation": {"artifactLocation": {"uri": include-chain-1.h",
                                             "uriBaseId": "PWD"},
                        "region": {"startLine": 5},
                        "contextRegion": {"startLine": 5,
                                          "snippet": {"text": "#include \"include-chain-1-2.h\"\n"}}},
   "id": 1,
   "relationships": [{"target": 0,
                      "kinds": ["includes"]},
                     {"target": 4,
                      "kinds": ["isIncludedBy"]}]},

effectively capturing the inclusion digraph in SARIF form:

 +-----------------------------------+ +----------------------------------+
 |"id": 0                            | |"id": 2                           |
 | error: "conflicting types for 'p';| | note: previous declaration of 'p'|
 |  have 'char'"|                    | | with type 'int'")                |
 | in include-chain-1-2.h            | | in include-chain-1-1.h           |
 +-----------------------------------+ +----------------------------------+
                   |                                      |
                   | included-by                          | included-by
                   V                                      V
  +--------------------------------+    +--------------------------------+
  |"id": 1                         |    |"id": 3                         |
  | #include "include-chain-1-2.h" |    | #include "include-chain-1-1.h" |
  | in include-chain-1.h           |    | in include-chain-1.h           |
  +--------------------------------+    +--------------------------------+
                         |                      |
                         | included-by          | included-by
                         V                      V
                  +------------------------------------+
                  |"id": 4                             |
                  | The  #include "include-chain-1.h"  |
                  | in include-chain-1.c               |
                  +------------------------------------+

Locations only gain "id" fields if they need one, and the precise
numbering of the IDs within a result is an implementation detail (the
order in which references to the locations are made).

To test all this non-trivial JSON from DejaGnu I needed to adapt the
python testing code used by gcov, adding a new run-sarif-pytest based
on run-gcov-pytest.

gcc/ChangeLog:
PR middle-end/107941
* diagnostic-format-sarif.cc: Define INCLUDE_LIST and INCLUDE_MAP.
(enum class location_relationship_kind): New.
(diagnostic_artifact_role::scanned_file): New value.
(class sarif_location_manager): New.
(class sarif_result): Derive from sarif_location_manager rather
than directly from sarif_object.
(sarif_result::add_related_location): Convert to vfunc
implementation.
(sarif_location::m_relationships_map): New field.
(class sarif_location_relationship): New.
(class sarif_ice_notification): Derive from sarif_location_manager
rather than directly from sarif_object.
(sarif_builder::take_current_result): New.
(sarif_builder::m_line_maps): New field.
(sarif_builder::m_cur_group_result): Convert to std::unique_ptr.
(sarif_artifact::add_role): Skip scanned_file.
(get_artifact_role_string): Handle scanned_file.
(sarif_location_manager::add_relationship_to_worklist): New.
(sarif_location_manager::process_worklist): New.
(sarif_location_manager::process_worklist_item): New.
(sarif_result::on_nested_diagnostic): Pass *this to
make_location_object.
(sarif_location::lazily_add_id): New.
(sarif_location::get_id): New.
(get_string_for_location_relationship_kind): New.
(sarif_location::lazily_add_relationship): New.
(sarif_location::lazily_add_relationship_object): New.
(sarif_location::lazily_add_relationships_array): New.
(sarif_ice_notification::sarif_ice_notification): Fix overlong line.
Pass *this to make_locations_arr.
(sarif_ice_notification::add_related_location): New.
(sarif_location_relationship::sarif_location_relationship): New.
(sarif_location_relationship::get_target_id): New.
(sarif_location_relationship::lazily_add_kind): New.
(sarif_builder::sarif_builder): Add "line_maps" param and use it
to initialize m_line_maps.
(sarif_builder::end_diagnostic): Update for m_cur_group_result
becoming a std::unique_ptr.  Don't append to m_results_array yet.
(sarif_builder::end_group): Append m_cur_group_result to
m_results_array here, rather than in end_diagnostic.
(sarif_builder::make_result_object): Pass result_obj to
make_locations_arr and to make_code_flow_object.
(sarif_builder::make_locations_arr): Add "loc_mgr" param and pass
it to make_location_object.
(sarif_builder::make_location_object): For two overloads, add
"loc_mgr" param and call add_any_include_chain on the location.
(sarif_builder::add_any_include_chain): New.
(sarif_builder::make_location_object): New overload.
(sarif_builder::make_code_flow_object): Add "result" param and
pass it to make_thread_flow_location_object.
(sarif_builder::make_thread_flow_location_object): Add "result"
param and pass it to make_location_object.
(sarif_builder::get_or_create_artifact): Handle scanned_file.
(sarif_output_format::~sarif_output_format): Assert that there
isn't a pending result.
(sarif_output_format::sarif_output_format): Add "line_maps" param
and pass it to m_builder's ctor.
(sarif_stream_output_format::sarif_stream_output_format): Add
"line_maps" param and pass it to base class ctor.
(sarif_file_output_format::sarif_file_output_format): Likewise.
(diagnostic_output_format_init_sarif_stderr): Pass "line_table"
global to format.
(diagnostic_output_format_init_sarif_file): Likewise.
(diagnostic_output_format_init_sarif_stream): Likewise.
(test_sarif_diagnostic_context::test_sarif_diagnostic_context):
Likewise.
(buffered_output_format::buffered_output_format): Likewise.
(selftest::test_make_location_object): Likewise.
(selftest::test_make_location_object): Create a sarif_result for
use when calling make_location_object.
* diagnostic.cc (diagnostic_context::finish): End any active
diagnostic groups.
(diagnostic_context::report_diagnostic): Assert that we're within
a diagnostic group.
* diagnostic.h (diagnostic_report_diagnostic): Add
begin_group/end_group pair around call to
diagnostic_context::report_diagnostic.
* selftest-diagnostic.cc (test_diagnostic_context::report): Add
begin_group/end_group pair around diagnostic_impl call.

gcc/testsuite/ChangeLog:
PR middle-end/107941
* gcc.dg/sarif-output/include-chain-1-1.h: New test.
* gcc.dg/sarif-output/include-chain-1-2.h: New test.
* gcc.dg/sarif-output/include-chain-1.c: New test.
* gcc.dg/sarif-output/include-chain-1.h: New test.
* gcc.dg/sarif-output/include-chain-2.c: New test.
* gcc.dg/sarif-output/include-chain-2.h: New test.
* gcc.dg/sarif-output/sarif-output.exp: New file.
* gcc.dg/sarif-output/sarif.py: New test, adapted from
g++.dg/gcov/gcov.py.
* gcc.dg/sarif-output/test-include-chain-1.py: New test.
* gcc.dg/sarif-output/test-include-chain-2.py: New test.
* lib/scansarif.exp (sarif-pytest-format-line): New, taken
from lib/gcov.exp.
(run-sarif-pytest): New, adapted from run-gcov-pytest in
lib/gcov.exp.

Signed-off-by: David Malcolm <dmalcolm@redhat.com>
15 files changed:
gcc/diagnostic-format-sarif.cc
gcc/diagnostic.cc
gcc/diagnostic.h
gcc/selftest-diagnostic.cc
gcc/testsuite/gcc.dg/sarif-output/include-chain-1-1.h [new file with mode: 0644]
gcc/testsuite/gcc.dg/sarif-output/include-chain-1-2.h [new file with mode: 0644]
gcc/testsuite/gcc.dg/sarif-output/include-chain-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/sarif-output/include-chain-1.h [new file with mode: 0644]
gcc/testsuite/gcc.dg/sarif-output/include-chain-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/sarif-output/include-chain-2.h [new file with mode: 0644]
gcc/testsuite/gcc.dg/sarif-output/sarif-output.exp [new file with mode: 0644]
gcc/testsuite/gcc.dg/sarif-output/sarif.py [new file with mode: 0644]
gcc/testsuite/gcc.dg/sarif-output/test-include-chain-1.py [new file with mode: 0644]
gcc/testsuite/gcc.dg/sarif-output/test-include-chain-2.py [new file with mode: 0644]
gcc/testsuite/lib/scansarif.exp