Skip to content

feat: S24.01 IWYU CI gate for include hygiene#260

Merged
DavidCozens merged 5 commits into
mainfrom
feat/iwyu-ci-gate
May 4, 2026
Merged

feat: S24.01 IWYU CI gate for include hygiene#260
DavidCozens merged 5 commits into
mainfrom
feat/iwyu-ci-gate

Conversation

@DavidCozens

Copy link
Copy Markdown
Owner

Purpose

Adds include-what-you-use (IWYU) as an opt-in CMake preset (iwyu) that surfaces
include-hygiene drift across Core, Platform, Example, and Tests. The preset can
be promoted to a required CI status check in a follow-up PR once any in-flight
PRs have merged.

Also lands the cleanup that the gate now finds clean: 30 public headers
narrowed to stop transitively re-exporting other headers, plus the test-side
follow-on.

Closes #255.

Change Description

Gate infrastructure (commit 1):

  • cmake/Iwyu.cmakeiwyu and iwyu-apply custom targets, driven via
    iwyu_tool.py over compile_commands.json. CMake's launcher mechanism
    (CMAKE_<LANG>_INCLUDE_WHAT_YOU_USE) ignores IWYU's exit code since 3.11,
    so the launcher pattern can't enforce findings — the custom-target pipeline
    pipes IWYU output through a project filter and uses that as the gate.
  • scripts/iwyu_filter.py — drops three classes of finding IWYU gets wrong
    on this codebase: redundant struct Foo; forward-decls (kept for
    MISRA/readability), <stdbool.h> removals on dual-language C+C++ headers
    (IWYU only sees the C++ side), and CppUTest/TestHarness.h removals (IWYU
    doesn't model TEST(...) macro expansion). Each rule documented inline.
  • cmake/cpputest.imp — directs IWYU to suggest the public CppUTest umbrella
    header rather than internal headers like <UtestMacros.h>.
  • .clang-tidy adds -modernize-deprecated-headers to the disable list. IWYU
    natively suggests C-style header names which is right for a C library;
    forcing C++ wrappers in tests was the two tools fighting each other.

Apply (commit 2):

  • 30 public Interface headers narrowed (no longer transitively re-export).
  • Source files made self-sufficient (each TU includes the headers for symbols
    it directly names).
  • Audience contract from CLAUDE.md preserved: app-code = 1 header
    (SolidSyslog.h), service-code = 1 header, setup-code = N headers, one per
    type constructed.
  • 13 test files needed manual additions where IWYU couldn't parse them due
    to the cascade of compile errors from the production-side narrowing
    (one-time bootstrap cost; the rest IWYU/fix_includes drove automatically).
  • 1021 spurious blank lines that fix_includes.py inserted between TEST(...)
    and { stripped via script across 46 test files.
  • 2 IWYU pragmas, both for genuinely dual-language C+C++ headers:
    Tests/Support/OpenSslFake.h keeps <stdbool.h>; Tests/TestUtils.h has
    the CppUTest include relocated inside #ifdef __cplusplus.
  • 1 structural reorder in Tests/BlockSequenceTest.cpp moves the TestHarness
    include out of an extern "C" block.

Container: IWYU is built from source against clang-19 in
CppUTestDockerClang (separate repo). The container SHA is not bumped in
this PR — the active feature-work clone is using the existing pinned SHA via
docker-compose, and bumping mid-flight would disrupt that. The follow-up PR
that flips analyze-iwyu to required will bump the SHA at the same time.

Test Evidence

All build presets verified locally via docker run:

Preset Result
debug (gcc) green, 1009 tests pass
clang-debug green, 1009 tests pass
sanitize (ASan + UBSan) green
coverage 100% lines, 100% functions
analyze-tidy green (after -modernize-deprecated-headers)
analyze-cppcheck green
analyze-format green
iwyu green

Sanity-check on the gate itself: synthetic #include <math.h> in
Core/Source/SolidSyslog.c is detected and the gate exits non-zero.

The gate is correctly limited to "when the code compiles, are its includes
minimal and complete?" — it can't catch missing-include cases that fail to
compile (IWYU can't parse broken files), but the existing build gates catch
those anyway.

Areas Affected

  • Core/Interface/, Core/Source/ — public headers narrowed; source files
    now include their own dependencies directly. No API behaviour changes.
  • Platform/Posix/, Platform/OpenSsl/, Platform/Atomics/ — same shape:
    narrowed public headers, self-sufficient sources.
  • Example/ — net-zero churn in setup-code header counts; mostly stdlib
    reordering and a few struct forward-decls.
  • Tests/ — 13 manual test fixes, 65 auto-driven test fixes, blank-line
    cleanup. Tier-4 per CLAUDE.md but in scope for the gate because narrowed
    production headers expose test consumers that relied on transitive includes.
  • Build tooling — new iwyu + iwyu-apply preset, cmake/Iwyu.cmake,
    cmake/cpputest.imp, scripts/iwyu_filter.py. .clang-tidy exclusion list
    grows by one rule.

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented May 4, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Too many files!

This PR contains 163 files, which is 13 over the limit of 150.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c382ad3e-4b6e-4c4c-ba61-884e7803af2f

📥 Commits

Reviewing files that changed from the base of the PR and between 9ec2827 and d1f6ddf.

📒 Files selected for processing (163)
  • .clang-tidy
  • CMakeLists.txt
  • CMakePresets.json
  • Core/Interface/SolidSyslogBlockDeviceDefinition.h
  • Core/Interface/SolidSyslogBlockStore.h
  • Core/Interface/SolidSyslogBufferDefinition.h
  • Core/Interface/SolidSyslogConfig.h
  • Core/Interface/SolidSyslogCrc16Policy.h
  • Core/Interface/SolidSyslogDatagram.h
  • Core/Interface/SolidSyslogDatagramDefinition.h
  • Core/Interface/SolidSyslogEndpoint.h
  • Core/Interface/SolidSyslogFileBlockDevice.h
  • Core/Interface/SolidSyslogFileDefinition.h
  • Core/Interface/SolidSyslogNullBuffer.h
  • Core/Interface/SolidSyslogNullSecurityPolicy.h
  • Core/Interface/SolidSyslogNullStore.h
  • Core/Interface/SolidSyslogResolver.h
  • Core/Interface/SolidSyslogResolverDefinition.h
  • Core/Interface/SolidSyslogSenderDefinition.h
  • Core/Interface/SolidSyslogStoreDefinition.h
  • Core/Interface/SolidSyslogStream.h
  • Core/Interface/SolidSyslogStreamDefinition.h
  • Core/Interface/SolidSyslogStreamSender.h
  • Core/Interface/SolidSyslogStructuredDataDefinition.h
  • Core/Interface/SolidSyslogSwitchingSender.h
  • Core/Interface/SolidSyslogUdpSender.h
  • Core/Source/SolidSyslog.c
  • Core/Source/SolidSyslogBlockDevice.c
  • Core/Source/SolidSyslogBlockStore.c
  • Core/Source/SolidSyslogBuffer.c
  • Core/Source/SolidSyslogCrc16Policy.c
  • Core/Source/SolidSyslogDatagram.c
  • Core/Source/SolidSyslogFile.c
  • Core/Source/SolidSyslogFileBlockDevice.c
  • Core/Source/SolidSyslogMetaSd.c
  • Core/Source/SolidSyslogNullBuffer.c
  • Core/Source/SolidSyslogNullSecurityPolicy.c
  • Core/Source/SolidSyslogNullStore.c
  • Core/Source/SolidSyslogResolver.c
  • Core/Source/SolidSyslogSender.c
  • Core/Source/SolidSyslogStore.c
  • Core/Source/SolidSyslogStream.c
  • Core/Source/SolidSyslogStreamSender.c
  • Core/Source/SolidSyslogStructuredData.c
  • Core/Source/SolidSyslogSwitchingSender.c
  • Core/Source/SolidSyslogTimeQualitySd.c
  • Core/Source/SolidSyslogUdpSender.c
  • DEVLOG.md
  • Example/Common/ExampleCommandLine.c
  • Example/Common/ExampleInteractive.c
  • Example/Common/ExampleInteractive.h
  • Example/Common/ExampleMtlsConfig.c
  • Example/Common/ExampleMtlsConfig.h
  • Example/Common/ExampleTcpConfig.c
  • Example/Common/ExampleTcpConfig.h
  • Example/Common/ExampleTlsConfig.c
  • Example/Common/ExampleTlsConfig.h
  • Example/Common/ExampleUdpConfig.c
  • Example/Common/ExampleUdpConfig.h
  • Example/SingleTask/SolidSyslogExample.c
  • Example/Threaded/ExampleTlsSender_OpenSsl.c
  • Example/Threaded/main.c
  • Platform/Atomics/Source/SolidSyslogStdAtomicOps.c
  • Platform/OpenSsl/Interface/SolidSyslogTlsStream.h
  • Platform/OpenSsl/Source/SolidSyslogTlsStream.c
  • Platform/Posix/Interface/SolidSyslogGetAddrInfoResolver.h
  • Platform/Posix/Interface/SolidSyslogPosixClock.h
  • Platform/Posix/Interface/SolidSyslogPosixDatagram.h
  • Platform/Posix/Interface/SolidSyslogPosixFile.h
  • Platform/Posix/Interface/SolidSyslogPosixHostname.h
  • Platform/Posix/Interface/SolidSyslogPosixMessageQueueBuffer.h
  • Platform/Posix/Interface/SolidSyslogPosixProcessId.h
  • Platform/Posix/Interface/SolidSyslogPosixTcpStream.h
  • Platform/Posix/Source/SolidSyslogGetAddrInfoResolver.c
  • Platform/Posix/Source/SolidSyslogPosixClock.c
  • Platform/Posix/Source/SolidSyslogPosixDatagram.c
  • Platform/Posix/Source/SolidSyslogPosixFile.c
  • Platform/Posix/Source/SolidSyslogPosixHostname.c
  • Platform/Posix/Source/SolidSyslogPosixMessageQueueBuffer.c
  • Platform/Posix/Source/SolidSyslogPosixProcessId.c
  • Platform/Posix/Source/SolidSyslogPosixTcpStream.c
  • Tests/BlockSequenceTest.cpp
  • Tests/BufferFake.c
  • Tests/BufferFake.h
  • Tests/BufferFakeTest.cpp
  • Tests/ClockFakeTest.cpp
  • Tests/DatagramFake.c
  • Tests/DatagramFake.h
  • Tests/DatagramFakeTest.cpp
  • Tests/Example/ExampleAppNameTest.cpp
  • Tests/Example/ExampleCommandLineTest.cpp
  • Tests/Example/ExampleIpsTest.cpp
  • Tests/Example/ExampleLanguageTest.cpp
  • Tests/Example/ExampleServiceThreadTest.cpp
  • Tests/Example/ExampleSwitchConfigTest.cpp
  • Tests/Example/SolidSyslogExampleTest.cpp
  • Tests/FileFake.c
  • Tests/FileFake.h
  • Tests/FileFakeTest.cpp
  • Tests/OpenSslFakeTest.cpp
  • Tests/OpenSslIntegration/BioPairStream.c
  • Tests/OpenSslIntegration/BioPairStream.h
  • Tests/OpenSslIntegration/SolidSyslogTlsStreamIntegrationTest.cpp
  • Tests/OpenSslIntegration/TlsTestCert.c
  • Tests/OpenSslIntegration/TlsTestCert.h
  • Tests/OpenSslIntegration/TlsTestServer.c
  • Tests/OpenSslIntegration/TlsTestServer.h
  • Tests/SenderFake.c
  • Tests/SenderFake.h
  • Tests/SenderFakeTest.cpp
  • Tests/SocketFakeTest.cpp
  • Tests/SolidSyslogAddressTest.cpp
  • Tests/SolidSyslogAtomicCounterTest.cpp
  • Tests/SolidSyslogBlockDeviceTest.cpp
  • Tests/SolidSyslogBlockStorePosixTest.cpp
  • Tests/SolidSyslogBlockStoreTest.cpp
  • Tests/SolidSyslogCrc16PolicyTest.cpp
  • Tests/SolidSyslogCrc16Test.cpp
  • Tests/SolidSyslogFileBlockDeviceTest.cpp
  • Tests/SolidSyslogFormatterTest.cpp
  • Tests/SolidSyslogGetAddrInfoResolverTest.cpp
  • Tests/SolidSyslogMetaSdTest.cpp
  • Tests/SolidSyslogNullBufferTest.cpp
  • Tests/SolidSyslogNullSecurityPolicyTest.cpp
  • Tests/SolidSyslogNullStoreTest.cpp
  • Tests/SolidSyslogOriginSdTest.cpp
  • Tests/SolidSyslogPosixClockTest.cpp
  • Tests/SolidSyslogPosixDatagramTest.cpp
  • Tests/SolidSyslogPosixFileTest.cpp
  • Tests/SolidSyslogPosixMessageQueueBufferTest.cpp
  • Tests/SolidSyslogPosixSysUpTimeTest.cpp
  • Tests/SolidSyslogPosixTcpStreamTest.cpp
  • Tests/SolidSyslogPrivalTest.cpp
  • Tests/SolidSyslogStdAtomicOpsTest.cpp
  • Tests/SolidSyslogStreamSenderTest.cpp
  • Tests/SolidSyslogSwitchingSenderTest.cpp
  • Tests/SolidSyslogTest.cpp
  • Tests/SolidSyslogTimeQualitySdTest.cpp
  • Tests/SolidSyslogTlsStreamTest.cpp
  • Tests/SolidSyslogUdpPayloadTest.cpp
  • Tests/SolidSyslogUdpSenderTest.cpp
  • Tests/SolidSyslogWindowsClockTest.cpp
  • Tests/SolidSyslogWindowsFileTest.cpp
  • Tests/SolidSyslogWinsockDatagramTest.cpp
  • Tests/StoreFake.c
  • Tests/StoreFake.h
  • Tests/StoreFakeTest.cpp
  • Tests/StreamFake.h
  • Tests/StreamFakeTest.cpp
  • Tests/StringFake.c
  • Tests/StringFake.h
  • Tests/StringFakeTest.cpp
  • Tests/Support/AtomicOpsFake.c
  • Tests/Support/AtomicOpsFake.h
  • Tests/Support/ClockFake.c
  • Tests/Support/ClockFake.h
  • Tests/Support/OpenSslFake.c
  • Tests/Support/OpenSslFake.h
  • Tests/Support/SocketFake.h
  • Tests/TestUtils.h
  • cmake/Iwyu.cmake
  • cmake/cpputest.imp
  • scripts/iwyu_filter.py

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/iwyu-ci-gate

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented May 4, 2026

Copy link
Copy Markdown
Contributor

☀️   Quality Summary

   🚦   build-linux-gcc: 100% successful (✔️ 1014 passed, 🙈 3 skipped)
   🚦   build-linux-clang: 100% successful (✔️ 963 passed, 🙈 3 skipped)
   🚦   sanitize-linux-gcc: 100% successful (✔️ 963 passed, 🙈 3 skipped)
   🚦   integration-linux-openssl: 100% successful (✔️ 9 passed)
   🚦   bdd-linux-syslog-ng: 100% successful (✔️ 45 passed)
   🚦   bdd-windows-otel: No test results available
   🚦   build-windows-msvc: No test results available
   ⚠️   Clang-Tidy: No warnings
   ⚠️   CPPCheck: No warnings


🚧   Error Messages

Quality Monitor Errors:
No matching report files found when using pattern '**/junit-bdd-windows-otel/TESTS-*.xml'! Configuration error for 'bdd-windows-otel'?
No matching report files found when using pattern '**/junit-build-windows-msvc/cpputest_*.xml'! Configuration error for 'build-windows-msvc'?

Created by Quality Monitor v1.14.0 (#f3859fd). More details are shown in the GitHub Checks Result.

DavidCozens and others added 5 commits May 4, 2026 09:10
New `iwyu` CMake preset runs include-what-you-use against the active
build's compile_commands.json, piped through a project-specific filter
that drops findings IWYU gets wrong on this codebase (redundant struct
forward-decls, dual-language stdbool.h confusion, CppUTest macro
invisibility). A custom CppUTest mapping file directs IWYU to suggest
the public TestHarness.h umbrella over the private internals. Also
disables modernize-deprecated-headers in clang-tidy: the library is C
and IWYU naturally suggests <stdint.h>-style names; forcing C++
wrappers on tests creates friction that doesn't earn its keep for an
embedded-friendly library.

This commit adds only the infrastructure — running the gate against
the existing tree would surface findings, fixed in the next commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…e, Tests

Mechanical apply of IWYU's surviving findings (after the project filter)
via fix_includes.py, then clang-format. Three classes of change:

- Public Interface headers narrowed: 30 headers stop transitively re-
  exporting other public headers. Audience contract from CLAUDE.md
  preserved (app/service code = 1 header; setup code = N headers, one
  per type constructed).
- Source files made self-sufficient: each TU now includes the headers
  for symbols it directly names rather than relying on transitive
  includes from its primary header.
- Test code follow-on: 13 test files needed manual additions where
  IWYU couldn't parse them due to compile errors caused by the
  narrowing (one-time bootstrap cost). 1021 spurious blank lines
  fix_includes.py inserted between TEST(...) and { stripped via script.

Two pragma annotations for genuinely dual-language (C+C++) headers:
- Tests/Support/OpenSslFake.h keeps <stdbool.h>
- Tests/TestUtils.h relocates the CppUTest include inside #ifdef __cplusplus

One structural reorder in Tests/BlockSequenceTest.cpp moves the
TestHarness include out of an extern "C" block where fix_includes.py
incorrectly placed it.

All build presets green (debug, clang-debug, sanitize, tidy, cppcheck,
coverage at 100% lines/functions). All 1009 tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Windows-only test files weren't in IWYU's Linux scope (they don't
appear in compile_commands.json on Linux), so the same hand-fix that
was applied to the POSIX equivalents is needed here. Caught by CI
build-windows-msvc.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
S18.03 expanded BlockSequenceTest with std::map / std::vector usage; the
post-rebase IWYU pass picked up the new dependencies on <cstddef> and
<utility>. Also strips fix_includes.py's spurious blank-lines-after-TEST
on this one file.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@DavidCozens DavidCozens force-pushed the feat/iwyu-ci-gate branch from 88b908f to d1f6ddf Compare May 4, 2026 08:14
@github-actions

github-actions Bot commented May 4, 2026

Copy link
Copy Markdown
Contributor

☀️   Quality Summary

   🚦   build-linux-gcc: 100% successful (✔️ 1025 passed, 🙈 3 skipped)
   🚦   build-linux-clang: 100% successful (✔️ 974 passed, 🙈 3 skipped)
   🚦   sanitize-linux-gcc: 100% successful (✔️ 974 passed, 🙈 3 skipped)
   🚦   integration-linux-openssl: 100% successful (✔️ 9 passed)
   🚦   bdd-linux-syslog-ng: 100% successful (✔️ 46 passed)
   🚦   bdd-windows-otel: 57% successful (✔️ 26 passed, 🙈 20 skipped)
   🚦   build-windows-msvc: 100% successful (✔️ 887 passed, 🙈 1 skipped)
   ⚠️   Clang-Tidy: No warnings
   ⚠️   CPPCheck: No warnings


Created by Quality Monitor v1.14.0 (#f3859fd). More details are shown in the GitHub Checks Result.

@DavidCozens DavidCozens merged commit 3b64613 into main May 4, 2026
14 checks passed
@DavidCozens DavidCozens deleted the feat/iwyu-ci-gate branch May 4, 2026 08:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

S24.01: IWYU CI gate for include hygiene

1 participant