Redundant Suspend
ID |
kotlin.redundant_suspend |
Severity |
low |
Remediation Complexity |
medium |
Remediation Risk |
low |
Remediation Effort |
medium |
Resource |
Code Smell |
Language |
Kotlin |
Tags |
code-style, concurrency |
Description
Reports functions declared suspend whose body cannot possibly invoke any
suspending function. The suspend modifier is meaningful only when the body
actually suspends (calls another suspend function, a coroutine primitive,
or a flow terminal operator). A suspend function whose body is a pure
expression cannot suspend; the modifier is pure overhead and forces every
caller to be suspend-aware for nothing.
Rationale
// Bad — body cannot suspend
suspend fun compute(x: Int): Int = x * 2
suspend fun greet(): String {
return "hi"
}
The compiler still threads continuation plumbing through these functions, and every caller has to be inside a coroutine to invoke them. The result is API noise without any benefit.
Remediation
Drop the suspend modifier. If the function is part of an interface whose
other members are suspending, leave it as is — the modifier may be a contract
choice rather than a smell.
fun compute(x: Int): Int = x * 2
fun greet(): String = "hi"
Exceptions
Detection is intentionally conservative — without full semantic typing the
rule cannot tell whether an arbitrary foo() call is suspending. It only
fires when the body has zero function calls and zero member-navigation
expressions, which is the strongest signal that the body cannot possibly
invoke a suspending function. Overrides, abstract, expect, and external
functions are skipped.