pinterest / ktlint

An anti-bikeshedding Kotlin linter with built-in formatter
https://pinterest.github.io/ktlint/
MIT License
6.06k stars 504 forks source link

Single-line chain method calls with operator #2712

Open hendraanggrian opened 1 week ago

hendraanggrian commented 1 week ago

I have two strings, both are single-line chain method calls that do not violate the max lines rule.

val left = result.value.drop(1).dropLast(1).lowercase()
val right = result.value.last()

When joined together with + operator, chain method continuation rule treats them as one statement. It demanded that the first chain be wrapped, but not the rest.

Expected Behavior

When there are mathematical and comparison operators, chained calls of each operand should be inspected individually. Alternatively, force multi-lining on the rest of the operands.

val s =
    result.value.drop(1).dropLast(1).lowercase() +
        result.value.last()

// or

val s =
    result.value
        .drop(1)
        .dropLast(1)
        .lowercase() +
        result.value
                .last()

Current Behavior

val s =
    result.value
        .drop(1)
        .dropLast(1)
        .lowercase() +
        result.value.last()

Additional information

paul-dingemans commented 5 days ago

When there are mathematical and comparison operators, chained calls of each operand should be inspected individually. Alternatively, force multi-lining on the rest of the operands.

This is exactly how the rule works. The outmost expression (parenthesis added for clarification) is (result.value.drop(1).dropLast(1).lowercase()) + (result.value.last()).

The first part of this expression, result.value.drop(1).dropLast(1).lowercase(), contains 4 chain operators, which as documented result in writing this expression as a multiline expression. The second subexpression has less than 4 chain operators, and as of that may be written as a single line.

When the first subexpression is shortened by remove one chain operation, you will see that the example is accepted by ktlint unchanged:

val s =
    result.value.drop(1).dropLast(1) +
        result.value.last()
hendraanggrian commented 10 hours ago

Hi Paul, thanks for clarifying. I missed the documented configuration of 4 chain method calls. However, explicitly setting ktlint_chain_method_rule_force_multiline_when_chain_operator_count_greater_or_equal_than to unset seems to have no effect in my test. It will revert back to 4 while the document states that it should disable the setting.

Using the original code, I can only pass the check when ktlint_chain_method_rule_force_multiline_when_chain_operator_count_greater_or_equal_than is set to 5 or more.

val s =
    result.value.drop(1).dropLast(1).lowercase() +
        result.value.last()