Skip to content

Add detekt for Kotlin static analysis#378

Open
holodorum wants to merge 4 commits intokson-org:mainfrom
holodorum:static-code-analysis
Open

Add detekt for Kotlin static analysis#378
holodorum wants to merge 4 commits intokson-org:mainfrom
holodorum:static-code-analysis

Conversation

@holodorum
Copy link
Copy Markdown
Collaborator

Introduces detekt across all Kotlin modules so new code is held to a consistent set of static-analysis rules.

How it's wired up

  • Rule config is authored in detekt.kson and transpiled to detekt.yml at build time. The generated .yml is gitignored — edit the .kson source of truth.
  • Each module ships a detekt-baseline.xml that grandfathers pre-existing findings. Detekt ignores these but still fails the build on anything new, so pre-existing debt can be paid down incrementally without blocking the rollout.
  • Existing findings that were quick to resolve have already been cleaned up; the rest sit in the baselines.

Refreshing baselines

Documented in the readme. Short version:

./gradlew detekt           # must be green — no new findings hiding
./gradlew detektBaseline   # regenerate snapshots
git diff '**/detekt-baseline.xml'   # should only show removals

Running locally

  ./gradlew detekt

Wires detekt 1.23.8 into the Gradle build, applied to every module that
uses the Kotlin multiplatform or JVM plugin. Configuration is authored in
detekt.kson and transpiled to detekt.yml via the existing
TranspileKsonToYaml task, mirroring how .circleci/config.kson is handled.
Pure style rules (MaxLineLength, WildcardImport, NewLineAtEndOfFile,
PackageNaming) are disabled to keep the focus on code-quality findings;
remaining findings are addressed in the follow-up commit.
Applies fixes for the actionable findings surfaced by the detekt setup
from the preceding commit, then tunes the config and baselines the
remaining structural debt so `./gradlew detekt` is green across every
module.

Code fixes:
  - Replace unused `for (i in 1..n)` counters with `repeat(n)` in
    Formatter.kt
  - Replace `throw IllegalArgumentException(...)` guards with
    `require(...)` / `requireNotNull(...)` in Message.kt and the schema
    ref test
  - Replace "should not happen" `RuntimeException` throws with the
    existing `ShouldNotHappenException` across the parser, the
    IntelliJ plugin highlighter / element type mapper, and LexerTest
  - Convert `KsonIcons` to an `object` (it was a utility class with
    a public constructor)
  - Remove the empty body of the `KsonStringValidatorTest` placeholder
    class; convert the constant-returning `searchExpressionSchema()`
    test helper to a `val`
  - Suppress `SwallowedException` at two intentional catch sites where
    the exception type itself carries the full semantic
  - Suppress `UnusedParameter` on the no-op native-test `validateYaml`
    stub, which must match the JVM signature

Config changes in `detekt.kson`:
  - Raise NestedBlockDepth to 6 and ComplexCondition to 10 to cover the
    existing parser/validator code without being pathological
  - Disable MatchingDeclarationName and TooGenericExceptionCaught — the
    former would force a wave of file renames; the latter collides with
    CLI commands that intentionally catch broadly to render
    user-facing errors

Baselines:
  - Per-module `detekt-baseline.xml` files capture the remaining
    LongMethod / LargeClass / CyclomaticComplexMethod / ThrowsCount /
    ReturnCount / LoopWithTooManyJumpStatements / SpreadOperator
    findings on existing code. New code is still scrutinized against
    every rule.
detekt.yml is transpiled from detekt.kson by transpileDetektConfigTask on
every build, so it should not live in version control. Adds the file to
.gitignore and removes the tracked copy from the index.
Adds a short section to the developer setup explaining what detekt does,
that detekt.kson is the source of truth (detekt.yml is generated), and
what the detekt-baseline.xml files carry: grandfathered pre-existing
findings so detekt only fails the build on new issues. Also documents
the "run detekt green, then detektBaseline, then diff" flow for safely
refreshing the baselines after paying down debt.
@aochagavia
Copy link
Copy Markdown
Collaborator

Interesting! Will CI fail when there are unaddressed detekt warnings? It sounds like something we might want.

@holodorum
Copy link
Copy Markdown
Collaborator Author

Yes, it should run with the check task

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