Skip to content

A somewhat opinionated ruleset for Detekt, primarily intended to avoid crashes and bugs related to mutability.

License

Notifications You must be signed in to change notification settings

hbmartin/hbmartin-detekt-rules

Repository files navigation

Hbmartin's detekt rules

Join the chat at #detekt on KotlinLang PR Checks codecov CodeFactor Maintainability Rating Maven Central Version

These are my opinions. There are many like them but these are mine. 😄

Quick Start

Inside of your dependencies block add the following: (for more details see adding more rule sets)

detektPlugins("me.haroldmartin:hbmartin-detekt-rules:0.1.7")

Then add to your detekt configuration as in the section below to activate rules. Note that the AvoidFirstOrLastOnList and AvoidMutableCollections rules require type resolution to be active.

Type Resolution

Some of these rules require type resolution, which typically happens when running detect*Main task. For more details (including instructions for multiplatform) see Using Type Resolution in the detekt docs.

If you rely on the check task to run detekt, you can replace the default detekt chek with a typed check using a configuration like:

tasks.named("check").configure {
     this.setDependsOn(
         this.dependsOn.filterNot {
             it is TaskProvider<*> && it.name == "detekt"
         } + tasks.named("detektMain"),
     )
 }

Configuration

Add below to your detekt.yml and modify to suit your needs. Only the AvoidVarsExceptWithDelegate rule has additional configuration options, where you may provide a regex to allow additional variable delegates.

HbmartinRuleSet:
  AvoidFirstOrLastOnList:
    active: true
  AvoidMutableCollections:
    active: true
  AvoidVarsExceptWithDelegate:
    active: true
    allowedDelegates:
      - 'remember\w*'
      - 'mutableState\w*'
  DontForceCast:
    active: true
  MutableTypeShouldBePrivate:
    active: true
  NoCallbacksInFunctions:
    active: true
    ignoreAnnotated: ['Composable']
    allowExtensions: true
    allowReceivers: true
    allowInline: false
  NoNotNullOperator:
    active: true
  NoVarsInConstructor:
    active: true
  WhenBranchSingleLineOrBraces:
    active: true

Rules

AvoidFirstOrLastOnList

Finds uses of .first() or .list() on a list type. These are dangerous calls since they will throw a NoSuchElementException exception if the list is empty. Prefer to use .firstOrNull() or .lastOrNull() instead. See here for triggering and non-triggering examples.

AvoidMutableCollections

Finds uses of mutable collections e.g. MutableList<>. These are highly likely to lead to bugs, prefer to use functional patterns to create new lists modified as needed. See here for triggering and non-triggering examples.

AvoidVarsExceptWithDelegate

Finds uses of mutable var fields. These are highly likely to lead to bugs, prefer to use a Flow or some reactive type for any mutable state. There is an exception made for vars which are implemented with the delegation pattern, which is particularly common when using Compose. See here for triggering and non-triggering examples.

DontForceCast

Finds uses of as to force cast. These are likely to lead to crashes, especially in unforeseen circumstances, prefer to safely cast with as? instead. See here for triggering and non-triggering examples.

MutableTypeShouldBePrivate

Finds publicly exposed mutable types e.g. MutableStateFlow<>. These are likely to lead to bugs, prefer to expose a non-mutable Flow (e.g. with _mutableStateFlow.asStateFlow()) or other non-mutable type. See here for triggering and non-triggering examples.

NoCallbacksInFunctions

Finds uses of callbacks in functions. This can lead to a mixed concurrency paradigm and are likely to lead to bugs or stalled threads, prefer to use a suspend function instead. Use the ignoreAnnotated configuration to allow callbacks in @Composable functions. See here for triggering and non-triggering examples.

NoNotNullOperator

Finds uses of !! to force unwrap. These are likely to lead to crashes, prefer to safely unwrap with ?. or ?: instead. Otherwise the Kotlin docs will make fun of you for being an NPE lover. See here for triggering and non-triggering examples.

NoVarsInConstructor

Finds uses of var in a constructor. These are likely to lead to bugs, always use val instead. See here for triggering and non-triggering examples.

WhenBranchSingleLineOrBraces

A stylistic rule that require that either a when expression be on a single line or use braces. Either case should have a single space after the arrow. See here for triggering and non-triggering examples.

Contributing

  • Jump in and modify this project! Start by cloning it with git clone git@github.com:hbmartin/hbmartin-detekt-rules.git, then open it in IntelliJ and run the tests.
  • Read the detekt documentation to learn more about how to write rules.
  • PRs and bug reports / feature requests are all welcome!
  • Checked with detekt, including the ruleauthors set and, of course, running these rules on itself 😏
  • Treat other people with helpfulness, gratitude, and consideration! See the JetBrains CoC

Authors