diff options
| author | David Malcolm <dmalcolm@redhat.com> | 2025-11-11 10:20:47 -0500 |
|---|---|---|
| committer | David Malcolm <dmalcolm@redhat.com> | 2025-11-11 10:23:13 -0500 |
| commit | 8a155c170b443e332b3db4922f0f0d588a17604f (patch) | |
| tree | cd7bb1a52906e5c57fd445ed812e95f1a4bb0e28 /contrib | |
| parent | 8fad025430b4fded6c9ebbc6bd4fd8ac4e8a2194 (diff) | |
diagnostics: add experimental SARIF JSON-RPC notifications for IDEs [PR115970]
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3358r0.html#msvc
describes a feature of Visual Studio 2022 version 17.8. which can send its
diagnostics in SARIF form to a pipe when setting the environment variable
SARIF_OUTPUT_PIPE:
https://learn.microsoft.com/en-us/cpp/build/reference/sarif-output?view=msvc-170#retrieving-sarif-through-a-pipe
The precise mechanism above involves Windows-specific details (windows pipes
and HANDLEs).
The following patch implements an analogous feature for GCC, using Unix
domain sockets rather than the Windows-specific details.
With this patch, GCC's cc1, cc1plus, etc will check if
EXPERIMENTAL_SARIF_SOCKET is set in the environment, and if so,
will attempt to connect to that socket. It will send a JSON-RPC
notification to the socket for every diagnostic emitted. Like the
MSVC feature, the diagnostics are sent one-at-a-time as SARIF
"result" objects, rather than sending a full SARIF "log" object.
The patch includes a python test script which runs a server.
Tested by running the script in one terminal:
$ ../../src/contrib/sarif-listener.py
listening on socket: /tmp/tmpjgts0u0i/socket
and then invoking a build in another terminal with the envvar
set to the pertinent socket:
$ EXPERIMENTAL_SARIF_SOCKET=/tmp/tmpjgts0u0i/socket \
make check-gcc RUNTESTFLAGS="analyzer.exp=*"
and watching as all the diagnostics generated during the build
get sent to the listener.
The idea is that an IDE ought to be able to create a socket and
set the environment variable when invoking a build, and then listen
for all the diagnostics, without needing to manually set build flags
to inject SARIF output.
This feature is experimental and subject to change or removal
without notice; I'm adding it to make it easier for IDE developers to
try it out and give feedback.
contrib/ChangeLog:
PR diagnostics/115970
* sarif-listener.py: New file.
gcc/ChangeLog:
PR diagnostics/115970
* diagnostics/sarif-sink.cc: Include <sys/un.h> and <sys/socket.h>.
(sarif_builder::end_group): Update comment.
(sarif_sink::on_end_group): Drop "final".
(class sarif_socket_sink): New subclass.
(maybe_open_sarif_sink_for_socket): New function.
* diagnostics/sarif-sink.h: (maybe_open_sarif_sink_for_socket):
New decl.
* doc/invoke.texi (EXPERIMENTAL_SARIF_SOCKET): Document new
environment variable.
* toplev.cc: Define INCLUDE_VECTOR. Add include of
"diagnostics/sarif-sink.h".
(toplev::main): Call
diagnostics::maybe_open_sarif_sink_for_socket.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
Diffstat (limited to 'contrib')
| -rwxr-xr-x | contrib/sarif-listener.py | 41 |
1 files changed, 41 insertions, 0 deletions
diff --git a/contrib/sarif-listener.py b/contrib/sarif-listener.py new file mode 100755 index 00000000000..92e38a698c2 --- /dev/null +++ b/contrib/sarif-listener.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 + +# Example listener for SARIF output to a socket. +# Copyright (C) 2025 Free Software Foundation, Inc. +# Contributed by David Malcolm <dmalcolm@redhat.com>. +# +# This file is part of GCC. +# +# GCC is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3, or (at your option) any later +# version. +# +# GCC is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. + +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. */ + +from pathlib import Path +from socketserver import UnixStreamServer, StreamRequestHandler, ThreadingMixIn +import tempfile + +class MyHandler(StreamRequestHandler): + def handle(self): + notification = self.rfile.read() + print(notification) + +class ThreadedUnixStreamServer(ThreadingMixIn, UnixStreamServer): + pass + +if __name__ == '__main__': + with tempfile.TemporaryDirectory() as tmpdir: + socket_path = Path(tmpdir) / 'socket' + with ThreadedUnixStreamServer(socket_path.as_posix(), + MyHandler) as server: + print('listening on socket: %s' % socket_path) + server.serve_forever() |
