Skip to content

feat: Add inline suppression comments for complexity thresholds#35

Merged
fummicc1 merged 2 commits into
mainfrom
feature/inline-suppression
Jul 15, 2026
Merged

feat: Add inline suppression comments for complexity thresholds#35
fummicc1 merged 2 commits into
mainfrom
feature/inline-suppression

Conversation

@fummicc1

@fummicc1 fummicc1 commented Jul 6, 2026

Copy link
Copy Markdown
Owner

Summary

Adds // swift-complexity:disable so a single, reviewed function can be exempted from threshold checks without raising the threshold globally or abandoning enforcement. This closes a real gap left by the per-type threshold work (#32): today, one legitimately complex function forces a choice between fixing it or weakening the check for the whole type.

Second step of the "Now" roadmap, after SARIF output (#33).

Syntax

// swift-complexity:disable
func parseLegacyFormat(_ input: String) -> Document { ... }

// swift-complexity:disable cognitive
func stateMachine(_ event: Event) { ... }  // cyclomatic is still checked
  • The comment must be the closest leading comment directly above the declaration it suppresses (function, initializer, deinitializer, or computed property/accessor).
  • A bare disable suppresses every metric; naming specific metrics (cyclomatic/cognitive, space- or comma-separated) suppresses only those.
  • Deliberately no "next line" form and no "enable" counterpart — suppression always scopes to exactly one declaration, so unlike range-based disable/enable there's nothing to forget to re-enable.
  • Fails closed on a typo: an unrecognized metric name suppresses nothing for that comment, rather than falling back to "suppress everything." A typo should not silently widen what a complexity tool hides.
  • /// doc comments are never mistaken for a directive.

Design notes

  • Suppressed values are still computed and shown in every output format — only the threshold judgment is skipped. This meant updating all three places that independently decide "does this function violate its threshold" so a suppressed metric can't leak through one of them: ThresholdConfiguration.isExceeded (feeds the exit code and the upstream filter shared by text/json/xml/xcode/sarif), the Xcode diagnostic (which reports both metrics in one combined message and keeps doing so — only the gating changes), and SARIF's per-metric result generation (which computes its own >= check independent of isExceeded).
  • LCOM4 class cohesion has no suppression yet — it's a type-level metric, not a per-function one, so it needs its own design. Left as a follow-up.
  • New --report-suppressions flag prints every suppressed function and its current metric values to stderr, so suppressions stay visible instead of silently accumulating.

Verification

  • swift test: 102 tests pass, including new coverage for SuppressionParser (bare disable, specific metrics, comma-separated, typo'd metric, unrelated comment, doc comment, false-prefix match like disableFoo), ThresholdConfiguration.isExceeded with suppression, Xcode diagnostics with partial/full suppression, and SARIF with partial suppression
  • E2E against a real fixture (Tests/SwiftComplexityCoreTests/Fixtures/suppressed_functions.swift) confirmed with the built CLI across text, xcode, and sarif formats at multiple thresholds, and --report-suppressions output
  • swift-format clean via lefthook pre-commit; no new markdownlint errors introduced (verified by diffing lint output against main)

https://claude.ai/code/session_01GaTHVDhSAx76RbLmVziLQu

Add // swift-complexity:disable so a reviewed function can be exempted
from threshold checks without raising the threshold globally or giving
up on enforcement, closing the gap left by the earlier per-type
threshold work: a single legitimately complex function otherwise forces
either fixing it or weakening the check for the whole type.

Design:
- The comment must be the closest leading comment directly above the
  suppressed declaration (function, initializer, deinitializer, or
  computed property/accessor). There is deliberately no "next line"
  form and no "enable" counterpart, since suppression always scopes to
  exactly the one declaration whose leading trivia holds the comment -
  unlike range-based disable/enable, this can't be left un-re-enabled
  by mistake.
- A bare disable suppresses every metric; naming specific metrics
  (cyclomatic/cognitive) suppresses only those, leaving the rest
  checked as usual.
- Parsing fails closed: an unrecognized metric name suppresses nothing,
  rather than falling back to "suppress everything". A typo should not
  silently widen what gets hidden from a tool whose entire purpose is
  to not let violations slip through.
- Suppressed values are still computed and shown in every output
  format; only the threshold judgment is skipped. This required
  updating all three places that independently decide "does this
  function violate its threshold" - ThresholdConfiguration.isExceeded,
  the Xcode diagnostic (which reports both metrics in one combined
  message and keeps doing so), and SARIF's per-metric result
  generation - so a metric suppression can't be bypassed through one
  of the three.
- LCOM4 class cohesion has no suppression yet: it's a type-level
  metric, not a per-function one, so it needs its own design and is
  left for a follow-up.

Also add --report-suppressions, which prints every suppressed function
and its current metric values to stderr, so suppression comments stay
visible instead of silently accumulating.

Claude-Session: https://claude.ai/code/session_01GaTHVDhSAx76RbLmVziLQu
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

📊 PR Analysis

Type Count
Swift files 12
Test files 4
Documentation 2
Configuration 0

📝 Large PR: Consider breaking this into smaller, focused PRs.


Automated analysis by swift-complexity CI

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

🔍 Complexity Analysis Results

✅ All functions are below the complexity threshold of 15.

This analysis was performed by swift-complexity itself.

Empty commit only, to re-trigger the WIP marketplace app's webhook,
which did not report a status for this PR's prior commits.

Claude-Session: https://claude.ai/code/session_01GaTHVDhSAx76RbLmVziLQu
@github-actions

Copy link
Copy Markdown

📊 PR Analysis

Type Count
Swift files 12
Test files 4
Documentation 2
Configuration 0

📝 Large PR: Consider breaking this into smaller, focused PRs.


Automated analysis by swift-complexity CI

@github-actions

Copy link
Copy Markdown

🔍 Complexity Analysis Results

✅ All functions are below the complexity threshold of 15.

This analysis was performed by swift-complexity itself.

@fummicc1
fummicc1 merged commit fa58463 into main Jul 15, 2026
7 checks passed
@fummicc1
fummicc1 deleted the feature/inline-suppression branch July 15, 2026 23:53
@fummicc1 fummicc1 added the enhancement New feature or improvement label Jul 18, 2026
fummicc1 added a commit that referenced this pull request Jul 18, 2026
Release includes SARIF output format (#33) and inline suppression
comments (#35).

Claude-Session: https://claude.ai/code/session_01GaTHVDhSAx76RbLmVziLQu
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or improvement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant