Skip to content

Repository files navigation

crap4swift

Find the code that's actually risky to change — complex and untested — in any Swift package or iOS app. Then hand your AI reviewer a measured risk map, not a blind diff.

CRAP (Change Risk Anti-Patterns) scores each function by combining cyclomatic complexity with test coverage:

CRAP(f) = CC(f)² · (1 − coverage(f))³ + CC(f)

Fully tested code scores its complexity; untested complexity blows up super-linearly — a function with 5 branches and no tests is CRAP 30; add tests and it drops to 5. The canonical threshold is 30; --strict uses 8 (Uncle Bob's stricter bar).

There was no CRAP tool for Swift. This is it.

Install

brew install JordanCoin/tap/crap4swift     # macOS, universal binary

Or grab a binary from Releases, or build from source with swift build -c release. See the CHANGELOG for what's new.

Quickstart

crap4swift can run your tests itself and score the result in one command:

# Swift package / server-side Swift (Linux-friendly)
crap4swift --spm .

# iOS app — runs `xcodebuild test` on a simulator for you
crap4swift --xcodeproj MyApp.xcodeproj --scheme MyApp --only-testing MyAppTests
CRAP    CC  COV   FUNCTION
132.0   11  0%    routeCheckout(…)   Services/Checkout.swift:5   ⚠️
3.1     3   78%   classify(…)        Utils/Classify.swift:1
2 functions · 1 over threshold 30

Exit codes are 0 clean · 1 usage error · 2 a function exceeded the threshold — so it gates CI out of the box.

PR review — the point

Scope to the functions a branch changed, fuse in SwiftLint, and emit a risk map an AI reviewer can reason about instead of guessing from a raw diff:

crap4swift --spm . --changed main --format review
{
  "summary": { "count": 1, "overThreshold": 1, "worst": "routeCheckout(…)" },
  "functions": [{
    "function": "routeCheckout(…)", "crap": 132, "complexity": 11, "coverage": 0,
    "overThreshold": true,
    "lint": [{ "rule": "force_cast", "severity": "Error", "line": 6 }]
  }]
}

Wire it into CI with the included GitHub Action, a pre-push hook, or the "AI creates the PR" flow — see docs/pr-review.md.

Coverage sources & options

Two "doors": crap4swift runs the tests itself, or you feed it coverage you already have.

Coverage flag Source
--spm <dir> runs swift test --enable-code-coverage
--xcodeproj <p> --scheme <s> runs xcodebuild test on a simulator
--llvm-json <f> llvm-cov export JSON
--xccov-json <f> / --xcresult <p> Xcode xccov report / result bundle
Option Effect
--threshold N / --strict gate threshold (default 30 / 8)
--changed <base> only report functions touched vs <base> (PR scope)
--missing pessimistic|optimistic|skip how to score functions with no coverage
--baseline <f> + --fail-regression fail only if a function got worse
--format human|json|review|sarif|html text · JSON · agent map · Code Scanning · dashboard
--exclude <substr> · --only-testing <t> skip paths · scope test targets

SwiftUI note: Xcode omits declarative View bodies from coverage, so the default --missing skip drops them rather than flagging every body; use --missing pessimistic to surface them.

How it works

Two language-specific halves feed a pure, dependency-free core:

  • Complexity — SwiftSyntax (the compiler's own parser), so result builders, macros, and SwiftUI DSL parse exactly. Counting matches SwiftLint's cyclomatic_complexity.
  • Coverage — llvm-cov (true per-line) and xccov (per-function) normalized behind one Coverage type.
  • Core — joins complexity to coverage by (file, line-range), never by symbol name; applies the missing-coverage policy, scores, sorts, gates.

Built test-first: parser tests validate against real captured llvm-cov / xccov output, matching their own summary numbers to the digit. Runs on a Linux CI runner for SPM / server-side Swift — no Mac required (iOS coverage needs a Mac to generate).

Credits

The CRAP metric is by Alberto Savoia & Bob Evans (crap4j, 2007). crap4swift builds on unclebob/crap4java — the direct inspiration and the --strict (8) threshold — and minikin/cargo-crap, whose module split and --missing policy shaped this design. Complexity counting follows SwiftLint.

License

MIT — see LICENSE.

About

Change Risk Anti-Patterns (CRAP) for Swift — find complex, untested code and hand an AI reviewer a measured risk map. SwiftSyntax + llvm-cov/xccov. PR-native, Linux-ready.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages