Skip to content

feat: Add inline suppression for LCOM4 class cohesion#39

Merged
fummicc1 merged 1 commit into
mainfrom
feature/lcom4-suppression
Jul 20, 2026
Merged

feat: Add inline suppression for LCOM4 class cohesion#39
fummicc1 merged 1 commit into
mainfrom
feature/lcom4-suppression

Conversation

@fummicc1

Copy link
Copy Markdown
Owner

Summary

Extends // swift-complexity:disable to type declarations (class/struct/actor) so a reviewed low-cohesion type can be exempted from LCOM4 judgments. Previously the only workaround was --exclude, which hides the whole file's complexity violations too.

Closes #36.

Syntax

// swift-complexity:disable lcom4
class LegacyOrderManager { ... }  // member functions are still checked

// swift-complexity:disable
struct ScatteredHelper { ... }    // bare form: suppresses the type's own metrics (= lcom4)

Design

  • Scope intersection: SuppressionParser now takes an applicableTo scope and intersects parsed metrics with it — FunctionDetector passes functionLevel (cyclomatic/cognitive), NominalTypeDetector passes typeLevel (lcom4). This yields three properties at once:
    • A bare disable means "every metric of this declaration itself": above a type it suppresses only lcom4 and never cascades to member functions (a dedicated test pins this).
    • A metric of the wrong level (lcom4 above a function, cyclomatic above a class) suppresses nothing — the fail-closed contract from feat: Add inline suppression comments for complexity thresholds #35 extends naturally.
    • JSON backward compatibility: without the intersection, adding lcom4 to SuppressedMetric.allCases would have leaked "lcom4" into the suppressedMetrics array of bare-disabled functions, changing v1.1.0 output. A test now pins the function set to {cyclomatic, cognitive}.
  • Values stay visible, judgments are skipped (same contract as feat: Add inline suppression comments for complexity thresholds #35): ClassCohesion gains an optional suppressedMetrics set; the LCOM4 value is still computed and shown everywhere. All three cohesion judgment sites are gated — the Xcode diagnostic, SARIF's lcom4_cohesion results, and the CLI's threshold filtering. The exit code needs no change because LCOM4 never influenced it.
  • --report-suppressions now also lists suppressed types with current LCOM4 values, and its help text mentions types.
  • CohesionSummary statistics and cohesionLevel classification are deliberately unchanged — they are data, not judgments.

Verification

  • swift test: 107 tests pass, including the first direct unit tests for NominalTypeDetector (type-level scoping fixture: bare/lcom4-scoped/unsuppressed/wrong-level/typo cases), a no-cascade test over member functions, parser scope-intersection tests, and a formatter test asserting a suppressed LCOM4=5 class produces no SARIF result and no Xcode diagnostic while remaining visible in JSON
  • E2E against the real LCOM4 path (--lcom4 --index-store-path): a suppressed LCOM4=3 class disappeared from xcode/sarif output while an identical unsuppressed twin still reported; --report-suppressions listed it; JSON kept both values
  • Function-level JSON output verified unchanged against the v1.1.0 fixtures (no lcom4 leakage)
  • swift-format clean; markdownlint error count identical to main

https://claude.ai/code/session_01GaTHVDhSAx76RbLmVziLQu

Extend // swift-complexity:disable to type declarations
(class/struct/actor) so a reviewed low-cohesion type can be exempted
from LCOM4 judgments without excluding its whole file via --exclude,
which would also hide the file's complexity violations. Closes #36.

Design:
- SuppressionParser now takes an applicableTo scope and intersects the
  parsed metrics with it: FunctionDetector passes
  SuppressedMetric.functionLevel (cyclomatic/cognitive),
  NominalTypeDetector passes SuppressedMetric.typeLevel (lcom4). A bare
  disable therefore means "every metric of this declaration itself" - a
  bare disable above a type suppresses only lcom4 and never cascades to
  member functions, and naming a metric of the wrong level (lcom4 above
  a function, cyclomatic above a class) suppresses nothing, keeping the
  fail-closed contract.
- The intersection also preserves the v1.1.0 JSON output: without it,
  adding the lcom4 case to SuppressedMetric.allCases would have leaked
  "lcom4" into the suppressedMetrics array of bare-disabled functions.
- ClassCohesion gains an optional suppressedMetrics set mirroring
  FunctionComplexity; the LCOM4 value is still computed and shown in
  every output format, only the judgments are skipped. All three
  cohesion judgment sites are gated: the Xcode diagnostic, SARIF's
  lcom4_cohesion results, and the CLI's threshold filtering. The exit
  code needs no change because LCOM4 never influenced it.
- --report-suppressions now also lists suppressed types with their
  current LCOM4 values.

Verified end-to-end against the real LCOM4 path (--lcom4 with an index
store): a suppressed LCOM4=3 class disappears from xcode/sarif output
while an identical unsuppressed twin still reports, values remain in
JSON, and the suppression is listed by --report-suppressions.

Claude-Session: https://claude.ai/code/session_01GaTHVDhSAx76RbLmVziLQu
@fummicc1 fummicc1 added the enhancement New feature or improvement label Jul 19, 2026
@github-actions

Copy link
Copy Markdown

📊 PR Analysis

Type Count
Swift files 12
Test files 3
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 09a30a4 into main Jul 20, 2026
7 checks passed
@fummicc1
fummicc1 deleted the feature/lcom4-suppression branch July 20, 2026 16:04
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.

[Feature]: Inline suppression for LCOM4 class cohesion

1 participant