ktfmt icon indicating copy to clipboard operation
ktfmt copied to clipboard

Lambdas following a statement can be treated as lambda arguments, breaking syntax

Open davwheat opened this issue 1 year ago • 1 comments

In one of our projects, we have a util named multiCatch which we can tack on to the end of a lambda to more easily follow set logic when catching multiple types of exception.

Here's some simplified example code from our repository:

fun doSearch() {
    _results.postValue(Resource.Loading());
        
    {
        performSearch(searchParams)
    }
    .multiCatch(
        SocketException::class,
        SocketTimeoutException::class,
        SSLException::class
    ) {
        // Activity suspended while parsing stream
        _results.postValue(Resource.Error(it, null))
    }
}

When we run ktfmt on this code, it removes the semicolon from the end of the first statement, and then moves the lambda to the end of that statement, making the Kotlin compiler interpret it as a lambda argument to postValue():

fun doSearch() {
    _results
        .postValue(Resource.Loading()) { performSearch(searchParams) }
        .multiCatch(SocketException::class, SocketTimeoutException::class, SSLException::class) {
            // Activity suspended while parsing stream
            _results.postValue(Resource.Error(it, null))
        }
}

In my opinion, ktfmt should either leave the syntax as-is with a semicolon, or it should wrap the lambda in brackets. It shouldn't change the syntax of the code as part of formatting.

davwheat avatar Apr 23 '24 08:04 davwheat

There is code looking for this but it fails when the lambda is part of a larger expression, like a call chain. Usually it wouldn't matter because there would be some other token between the semicolon and the lambda.

The fix is probably to walk up to the statement containing semicolon, then down the left side of the next sibling statement.

nreid260 avatar Apr 26 '24 06:04 nreid260