Skip to content

Raise the cognitive-complexity threshold to 30 and clear the rest - #273

Merged
helly25 merged 1 commit into
mainfrom
clang_tidy_complexity
Aug 8, 2026
Merged

Raise the cognitive-complexity threshold to 30 and clear the rest#273
helly25 merged 1 commit into
mainfrom
clang_tidy_complexity

Conversation

@helly25

@helly25 helly25 commented Aug 8, 2026

Copy link
Copy Markdown
Owner

Third clang-tidy triage PR. Clears all 37 readability-function-cognitive-complexity findings, touching 6 files instead of 20.

The threshold was not the real problem

Of the 37 findings at threshold 25, only 9 were production functions. The other 28 were gtest TestBody, where the complexity is ASSERT_* macros expanding to branches — not logic anyone should refactor.

threshold production over tests over
25 (was) 9 28
30 (now) 5 22
35 2 20
60 0 3

No threshold fixes the tests — TestBody reaches 122 — and one high enough to clear them makes the check decorative for production code. IgnoreMacros looked like the obvious lever but measured too blunt: it silences all 37 including the genuine ones, because it excuses any function touching a macro rather than discounting macro-contributed complexity.

Threshold 30, and tests handled once

Threshold 30 clears the four borderline production functions (26, 29, 29, 30) that are dense-but-fine, while still flagging 32/34/35/39/54.

Tests are relaxed in tools/clang_tidy.sh, which lints *_test.cc with the check appended as disabled.

This cannot be expressed in .clang-tidy: its schema is exactly Checks, CheckOptions, WarningsAsErrors, HeaderFilterRegex, ExcludeHeaderFilterRegex, HeaderFileExtensions, ImplementationFileExtensions, FormatStyle, SystemHeaders, User — there is no per-file-pattern section, and its only granularity is per directory, which cannot separate tests that live beside the code they test.

Doing it in the hook means one statement of the rule instead of the same NOLINT comment on 24 tests, and new tests are covered without anyone remembering to annotate them. --checks appends to the configured Checks (verified), so tests keep every other check.

The five production functions, case by case

  • mope_main.cc Process (39) — split. Its complexity was almost entirely one nested block parsing --set=<key>=<value> (a section-path loop inside a branch inside a loop). Extracted as ApplySetFlag, leaving Process a linear pipeline.
  • FindMiddleSnake (54) — suppressed. The forward/reverse D-path search is one algorithm from Myers' paper; the two diagonal windows, parity rule and overlap test only make sense read together.
  • AppendSideBySide (35), AppendContext (34) — suppressed. The branching is the diff output format — row kinds, gutter markers, padding, truncation. That text is the contract these functions exist to produce.
  • ExpandInternal (32) — suppressed. Two over the threshold; one scan dispatching on tag kind.

Each suppression carries its own reason rather than a boilerplate one.

Test

  • The relaxation is scoped, not blanket: with its NOLINT removed a production file reports the finding again (1), restored it reports none, and test files and mixed test+production invocations report none. A production file still gets fully linted (149 findings from other checks).
  • bazel test --config=clang //mbo/mope/...:all //mbo/diff:all — 12/12 pass. The --set refactor is covered by //mbo/mope/tests/args, including the nested section:enabled,:config_start=25 path that exercises the extracted branch.
  • pre-commit run -a green.

@helly25
helly25 force-pushed the clang_tidy_complexity branch from 6d87797 to 341f6fa Compare August 8, 2026 17:19
The threshold was never the real problem: of 37 findings at 25, only 9
were production functions -- the other 28 were gtest `TestBody`, where
the complexity is ASSERT_* macros expanding to branches rather than logic
anyone should refactor. No threshold fixes that (TestBody reached 122),
and IgnoreMacros was measured too blunt: it silenced all 37, including
the genuine ones.

So: threshold 30, which clears the four borderline production functions
(26, 29, 29, 30) while still flagging 32/34/35/39/54.

Tests are handled once, in tools/clang_tidy.sh, which now lints
`*_test.cc` with the check appended as disabled. clang-tidy has no way to
express this in .clang-tidy -- its schema has no per-file-pattern section
and its only granularity is per directory, which cannot separate tests
that live beside the code they test. Doing it in the hook keeps one
statement of the rule instead of the same NOLINT comment on every test,
and covers new tests without anyone remembering to annotate them.
`--checks` appends to the configured `Checks`, so tests keep every other
check.

The five production functions, case by case:
  * mope_main.cc Process (39) - split. Its complexity was almost entirely
    one nested block parsing `--set=<key>=<value>`; extracted as
    ApplySetFlag. Covered by //mbo/mope/tests/args, including the nested
    `section:enabled,:config_start=25` path.
  * FindMiddleSnake (54), AppendSideBySide (35), AppendContext (34),
    ExpandInternal (32) - suppressed, each with its own reason. The first
    is one algorithm from Myers' paper whose bookkeeping only reads as a
    whole; the diff formatters' branching IS the output format they
    exist to specify.

Verified that the relaxation is scoped: with its NOLINT removed a
production file reports the finding again, while test files and mixed
invocations report none.

Signed-off-by: helly25 <6420169+helly25@users.noreply.github.com>
@helly25
helly25 enabled auto-merge (squash) August 8, 2026 18:17
@helly25
helly25 requested a review from Fab-Cat August 8, 2026 18:17
@helly25
helly25 force-pushed the clang_tidy_complexity branch from 8b96584 to 75b66e2 Compare August 8, 2026 18:19
@helly25
helly25 merged commit 1ba1405 into main Aug 8, 2026
23 checks passed
@helly25
helly25 deleted the clang_tidy_complexity branch August 8, 2026 19:02
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.

2 participants