https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107941
--- Comment #6 from GCC Commits <cvs-commit at gcc dot gnu.org> --- The master branch has been updated by David Malcolm <dmalc...@gcc.gnu.org>: https://gcc.gnu.org/g:4d1f71d49e396cb879d43dc96dc591079af66bbe commit r15-2354-g4d1f71d49e396cb879d43dc96dc591079af66bbe Author: David Malcolm <dmalc...@redhat.com> Date: Fri Jul 26 20:37:31 2024 -0400 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 <dmalc...@redhat.com>