Skip to content

tooling: fix the compile DB so clang-tidy-22 parses clean - #405

Merged
helly25 merged 1 commit into
mainfrom
tooling/clang-tidy-cdb
Aug 8, 2026
Merged

tooling: fix the compile DB so clang-tidy-22 parses clean#405
helly25 merged 1 commit into
mainfrom
tooling/clang-tidy-cdb

Conversation

@helly25

@helly25 helly25 commented Aug 8, 2026

Copy link
Copy Markdown
Owner

Ports the compile-DB fix from mbo #270 and adds the xff-specific <version>-shadow fix, so clang-tidy-22 parses cleanly again (it previously aborted on every TU). Unblocks #166.

Two root causes, both fixed

  1. Wrong compiler in the DB (mbo docs(TODO): SI-vs-binary byte-unit consistency #270). compile_commands-update.sh ran refresh_all --config=clang, but --config=clang only configures the extractor tool's own build and never reaches the internal aquery, so every recorded command named the autodetected Apple clang, not the hermetic toolchain → 'concepts'/'time.h' file not found. Port: bump the extractor pin to 6eb3ff1 (adds --bcce-prefer-target-config, which drops 227 duplicate exec-config entries), resolve the hermetic clang++ and pass --bcce-compiler + --bcce-prefer-target-config after --, plus Darwin-only --bcce-copt=-isysroot. New //tools:show_compiler probe materializes the toolchain on a fresh checkout.
  2. xff-specific <version> shadow. mbo is on the -isystem search path and ships a plain-text file literally named version at its root, which shadows libc++'s <version> (an explicit -isystem beats the compiler's builtin libc++). clang_tidy.sh now prepends the hermetic libc++ dir via --extra-arg-before=-isystem so the real <version> wins.

Also fixes a dead .clang-tidy option (CharTypdefsToIgnoreCharTypedefsToIgnore, surfaced by --verify-config).

Result

tools/clang_tidy.sh on a TU now yields real findings only - no concepts/version abort, no "too many errors". Tooling-only change (no //... target affected). The hook stays stages: [manual].

Follow-ons (#166)

  • A report-only CI job (continue-on-error) that builds the DB + runs the hook.
  • The residual-finding sweep (incl. the noisy new-in-22 cppcoreguidelines-pro-bounds-avoid-unchecked-container-access), then drop stages: [manual] to gate.

 + xff fix)

clang-tidy-22 aborted on every TU. Two causes, both fixed:

1) compile_commands-update.sh ran `refresh_all --config=clang`, but that flag
   only configures the extractor tool's own build, never the internal aquery,
   so every recorded command named the autodetected Apple clang, not the
   hermetic toolchain (-> 'concepts'/'time.h' not found). Port mbo #270: bump
   the extractor pin to 6eb3ff1 (adds --bcce-prefer-target-config, dropping 227
   duplicate exec-config entries), resolve the hermetic clang++ and pass
   --bcce-compiler + --bcce-prefer-target-config after --, plus Darwin-only
   --bcce-copt=-isysroot. Add //tools:show_compiler as the probe target that
   materializes the toolchain on a fresh checkout.

2) xff-specific: mbo is on the -isystem search path and ships a plain-text file
   named `version` at its root, which shadows libc++'s <version> (an explicit
   -isystem beats the compiler's builtin libc++). clang_tidy.sh now prepends the
   hermetic libc++ dir via --extra-arg-before=-isystem so the real <version>
   wins (hermetic libc++, matching the DB's clang, not the SDK's).

Also fix the dead .clang-tidy option (CharTypdefsToIgnore -> CharTypedefsToIgnore).

clang-tidy-22 now parses clean (real findings only, no abort). The hook stays
stages:[manual]; the report-only CI job + the residual-finding sweep are the
follow-ons (#166).
@helly25
helly25 enabled auto-merge (squash) August 8, 2026 16:19
@helly25
helly25 merged commit 64f16ad into main Aug 8, 2026
9 checks passed
@helly25
helly25 deleted the tooling/clang-tidy-cdb branch August 8, 2026 16:30
helly25 added a commit that referenced this pull request Aug 8, 2026
The #405 comment narrated the fork's own changelog (which PR added which
--bcce flag); that is the referenced module's history, not xff's to carry.
Keep only the xff-relevant fact: it is the helly25 fork and our script uses
its --bcce-* flags.
helly25 added a commit that referenced this pull request Aug 8, 2026
… a hard gate (#413)

* clang-tidy #166: sweep the test tree clean and flip clang-tidy to a hard gate

Clears the ~100 clang-tidy findings in the _test.cc files (the report-only CI
job surfaced them), so the whole tree is now clang-tidy-clean, then promotes the
CI clang-tidy job from report-only to a hard gate.

Test findings, fixed the genuine way (no blanket suppressions):
- optional access: EXPECT_THAT(opt, Optional(matcher)) for value-matches (fields);
  an if-guarded RenderIndex() helper for render-then-check cases (help_render);
  compute the expected instant with absl::FromCivil instead of deref (datetime).
- const-correctness (ignore/repo/license locals); use the unqualified matchers via
  the using-decls (hash IsTrue/IsFalse); std::ranges::is_sorted (license);
  (void)std::remove for best-effort cleanup (cert-err33); bugprone-argument-comment
  names matched to the real parameters (color); short test locals renamed
  (t->now, c->cfg, b->parts, lambda p->path); walk_test perf (const methods,
  reserve, std::cmp sign compare, emplace_back).
- Documented file-scoped suppressions only where the finding fights a mandated
  test idiom: gtest struct-fixture SetUp/TearDown visibility + `_`-suffixed
  members + data-heavy TEST_F cognitive-complexity (pager/walk), and
  single-threaded env-mutating fixtures (setenv/getenv).

Gate:
- .github/workflows/main.yml: drop `continue-on-error` from the clang-tidy step so
  any finding fails the job (and `done`). The compile-DB build already gated.
- .pre-commit-config.yaml: refresh the clang-tidy hook description (it is now the
  CI gate, not local-only; the compile-DB parse abort was fixed in #405). Keeps
  `stages: [manual]` so the CI job's `--hook-stage manual` invocation still runs it
  and local commits are not slowed.

Also: STYLE_CPP.md - rewrite the stale clang-tidy toolchain paragraph (it still
described trunk + WarningsAsErrors:true + "CI does not run it"; now the local
tools/clang_tidy.sh hook + compile_commands-update.sh + the CI clang-tidy gate).

Verified: full //xff/... suite green (92); the whole tree is clang-tidy-clean under
the hermetic clang-22 (confirmed by re-sweep).

* clang-tidy #166: fix Linux __config_site parse breakage + adopt mbo's test-pass split

The gate CI run surfaced two things, both in the tooling not the tree:

1. Linux libc++ parse collapse. tools/clang_tidy.sh prepends the hermetic
   `-isystem .../include/c++/v1` (to beat mbo's root `version` file winning
   `#include <version>`). libc++'s <__config> does `#include <__config_site>`, a
   generated per-target header. On Linux the hermetic install puts it in a
   target-triple subdir (include/<triple>/c++/v1/__config_site), NOT next to
   <__config>; macOS puts both in c++/v1. Prepending only c++/v1 then won the
   search for <__config> but hid <__config_site>, so libc++ failed to configure
   and the whole parse collapsed - std::string_view resolved to `int` and
   clang-tidy emitted a flood of spurious findings (member-init, convert-to-static
   on override methods, implicit-bool 'string_view -> int'). That is the
   "'__config_site' file not found" in the CI log. Fix: also prepend the directory
   that actually holds __config_site, located dynamically so it works on both the
   macOS (same dir, skipped) and Linux (triple subdir) layouts.

2. Adopt helly25/mbo's clang_tidy.sh test-pass split instead of scattering NOLINTs.
   Sources and *_test.cc run as two passes; the test pass appends
   `--checks=-readability-function-cognitive-complexity,-misc-override-with-different-visibility`
   (which APPENDS to .clang-tidy, removing just those two): gtest EXPECT/ASSERT
   macros inflate cognitive-complexity, and our mandated `struct` fixtures make
   SetUp/TearDown overrides public vs ::testing::Test's protected. One statement of
   each rule, covering new tests automatically. concurrency-mt-unsafe is
   deliberately NOT blanket-disabled: env-touching tests keep a targeted NOLINT.

Verified locally (hermetic clang-22, correct parse): all 43 _test.cc clean under
the two-pass; globals_test clean in isolation.

* clang-tidy #166: pin libc++ in the compile DB (fix the Linux stdlib mix)

The real root cause of the Linux-only phantom findings: the hermetic clang
compiles against libc++ on macOS but the system libstdc++ on Linux (the
toolchains_llvm default). tools/clang_tidy.sh prepends the hermetic libc++
`include/c++/v1` so `#include <version>` beats helly25_mbo's plain-text `version`
file (its -isystem'd repo root otherwise shadows it) - which on Linux injected
libc++ headers into a libstdc++ parse. That stdlib mix silently corrupted
clang-tidy's semantic analysis and produced a flood of contradictory phantom
findings: std::string_view resolving to `int`, misc-const-correctness on a
variable that IS mutated, readability-convert-member-functions-to-static on
`override` methods, member-init on aggregates. None reproduce on macOS (all
libc++), which is why the local sweep was clean.

Fix: always parse with libc++.
- compile_commands-update.sh: add `--bcce-copt=-stdlib=libc++` so every recorded
  command uses the hermetic clang's own libc++ on every platform. clang-tidy is
  then internally all-libc++ and the `<version>` prepend is consistent (as on
  macOS), so the phantom findings disappear at the source.
- tools/clang_tidy.sh: revert the __config_site triple-dir hunt from the previous
  commit; with libc++ actually active its builtin provides <__config_site>, and
  the hunt risked picking a wrong-triple config.
- .clang-tidy: disable cppcoreguidelines-pro-type-member-init + its alias
  hicpp-member-init. It forces blind initialization of every field rather than
  flagging a real defect; genuinely-unused members/vars are a different, useful
  check and stay on.

Verified: repo_test + walk_test clean on macOS with the libc++-pinned DB (the
earlier phantom findings in both were the stdlib mix). Linux CI on this PR is the
proof.

* clang-tidy #166: build the headers the compile DB references before linting

With libc++ pinned the Linux parse is correct, and the only remaining CI errors
were generated / virtual-include headers not on disk:
  'xff/license/notice.h' file not found
  'xff/regex/backend.h' file not found
Both come from the local @xff_extras_api module and are served through bazel-out
`_virtual_includes` symlink forests that exist only once the owning cc_library is
built. compile_commands-update.sh builds the DB but not those outputs, so a fresh
runner had the include paths recorded but the files absent - which surfaced as the
"some sources were not generated" symptom.

Fix: the clang-tidy CI job now runs `bazel build //...` before generating the DB,
materializing every genrule output and _virtual_includes forest. It is a plain
default-config build (NOT --config=clang): refresh_all records the DB in the
default config (`<cpu>-fastbuild`), so the forests must land there;
--config=clang would place them under a different output dir and miss. Headers do
not depend on which compiler compiles the .cc, so the default toolchain is correct
for materializing them.

(helly25/mbo builds only the `kind("generated file")` targets with --config=clang;
that works there because mbo's are config-invariant genrule outputs. xff's are
cc_library virtual-includes from an external module, so it needs the default-config
whole build instead.)
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.

1 participant