summaryrefslogtreecommitdiff
path: root/contrib
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2025-11-11 10:20:47 -0500
committerDavid Malcolm <dmalcolm@redhat.com>2025-11-11 10:23:13 -0500
commit8a155c170b443e332b3db4922f0f0d588a17604f (patch)
treecd7bb1a52906e5c57fd445ed812e95f1a4bb0e28 /contrib
parent8fad025430b4fded6c9ebbc6bd4fd8ac4e8a2194 (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-xcontrib/sarif-listener.py41
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()