Skip to content

Latest commit

Β 

History

193 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Hbmartin's detekt rules

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

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:1.0.0")

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

Type Resolution

Some of these rules require type resolution, which typically happens when running a detekt*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 check 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. In addition to the rule-specific options shown, every rule supports detekt's standard options such as ignoreAnnotated and excludes β€” e.g. ignoreAnnotated: ['Test'] on NoNotNullOperator allows !! in annotated test functions.

HbmartinRuleSet:
  AvoidFirstOrLastOnList:
    active: true
    # accessors to forbid; each must have an *OrNull equivalent
    methods:
      - 'first'
      - 'last'
      - 'single'
      - 'elementAt'
      - 'reduce'
      - 'reduceRight'
      - 'max'
      - 'min'
      - 'maxBy'
      - 'minBy'
  AvoidGlobalScope:
    active: true
  AvoidMutableCollections:
    active: true
    # set true to allow mutable collections in private declarations and function bodies
    allowPrivateAndLocal: false
  AvoidToIntOrThrowingConversions:
    active: true
    # String conversions to forbid; each must have an *OrNull equivalent
    methods:
      - 'toInt'
      - 'toLong'
      - 'toShort'
      - 'toByte'
      - 'toDouble'
      - 'toFloat'
      - 'toUInt'
      - 'toULong'
      - 'toUShort'
      - 'toUByte'
      - 'toBigDecimal'
      - 'toBigInteger'
      - 'toBooleanStrict'
  AvoidVarsExceptWithDelegate:
    active: true
    allowedDelegates:
      - 'remember\w*'
      - 'mutableState\w*'
  DontForceCast:
    active: true
  MutableTypeShouldBePrivate:
    active: true
    # regexes of mutable type names allowed to be exposed publicly
    allowedTypes: []
  NoCallbacksInFunctions:
    active: true
    ignoreAnnotated: ['Composable']
    allowExtensions: true
    allowReceivers: true
    allowInline: false
  NoDeferredResultInPublicApi:
    active: true
  NoLateinitVar:
    active: true
    # annotations that permit a lateinit var, e.g. ['Inject']
    allowedAnnotations: []
  NoNotNullOperator:
    active: true
  NoRunBlocking:
    active: true
  NoVarsInConstructor:
    active: true
  WhenBranchSingleLineOrBraces:
    active: true

Rules

AvoidFirstOrLastOnList

Finds uses of throwing accessors such as .first(), .last(), or .single() on a List, Array, or Sequence, including safe calls, calls with a predicate, and method references. These are dangerous calls since they will throw a NoSuchElementException if no matching element is present. Prefer the *OrNull variants, e.g. .firstOrNull() or .lastOrNull(), instead. The set of forbidden accessors is configurable via the methods option. See here for triggering and non-triggering examples.

AvoidGlobalScope

Finds uses of GlobalScope. Coroutines launched in GlobalScope are not bound to any lifecycle, so they leak work, are not cancelled on failure, and swallow crashes. Prefer a structured CoroutineScope, e.g. viewModelScope or lifecycleScope on Android. 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. Usages inside the standard library collection builders (buildList, buildSet, buildMap) and platform types from Java interop are not reported, and the allowPrivateAndLocal option can allow mutable collections in private declarations and function bodies. See here for triggering and non-triggering examples.

AvoidToIntOrThrowingConversions

Finds String conversions such as .toInt() that throw NumberFormatException on malformed input. Prefer the *OrNull variants, e.g. .toIntOrNull(), and handle the null case. The set of forbidden conversions is configurable via the methods option. 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. Type names matching a regex in the allowedTypes option are permitted. 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.

NoDeferredResultInPublicApi

Finds public functions and properties with an explicitly declared Deferred type. Returning a Deferred leaks the concurrency implementation to callers and makes crashes hard to trace, prefer a suspend function returning the awaited value. See here for triggering and non-triggering examples.

NoLateinitVar

Finds lateinit var properties. Accessing a lateinit property before initialization crashes with UninitializedPropertyAccessException, and lateinit forces mutability. Prefer constructor parameters, a nullable val, or lazy initialization. Annotations that legitimately require lateinit, e.g. @Inject, can be permitted with the allowedAnnotations option. 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. To allow !! in tests, use ignoreAnnotated: ['Test'] or an excludes glob on this rule. See here for triggering and non-triggering examples.

NoRunBlocking

Finds calls to runBlocking, which blocks the current thread until its coroutine finishes and can deadlock or freeze the UI when used on a main thread. Prefer exposing suspend functions and launching coroutines from a structured CoroutineScope. 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.
  • Each rule class carries KDoc with <noncompliant>/<compliant> examples β€” treat that KDoc as the canonical description when updating this README or the default config.yml.
  • 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

About

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

Topics

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Used by

Contributors

Languages