Then tell us:
- What language is this for?
Kotlin
- Which rule?
kotlin:S6311
- Why do you believe it’s a false-positive/false-negative?
The rule is incorrectly triggered when a CoroutineExceptionHandler
is provided as part of the CoroutineContext
to a coroutine builder like launch
, even if no specific Dispatcher
is provided alongside it.
In Kotlin coroutines, the context passed to launch
(or other builders) can contain multiple elements, including a Job
, a Dispatcher
, a CoroutineName
, and a CoroutineExceptionHandler
. Providing only an ExceptionHandler
in the context argument to launch
does not change the Dispatcher
the coroutine runs on; it inherits the dispatcher from the parent scope. The purpose of providing the handler is solely for centralized exception management within that coroutine, not for thread switching.
Therefore, flagging launch(myExceptionHandler) { suspendingFunction() }
seems incorrect, as it doesn’t violate the principle the rule aims to enforce (avoiding unnecessary thread switching for non-blocking suspend functions). It’s treating the presence of any context element, specifically the CoroutineExceptionHandler
, as if it implies a thread switch, which is not the case.
- Are you using
SonarQube Cloud
- How can we reproduce the problem? Give us a self-contained snippet of code (formatted text, no screenshots)
val dummyExceptionHandler = CoroutineExceptionHandler { context: CoroutineContext, throwable: Throwable ->
println("Caught exception in context $context: ${throwable.message}")
}
val exampleScope = CoroutineScope(Dispatchers.Default + SupervisorJob())
suspend fun callee() {
delay(10)
println("Callee finished successfully.")
}
fun caller() {
// This line is incorrectly flagged by S6311
exampleScope.launch(dummyExceptionHandler) {
callee()
}
}