Fix false negative MultilineLambdaItParameter on complex multiline single statement#5397
Conversation
| super.visitLambdaExpression(lambdaExpression) | ||
| val size = lambdaExpression.bodyExpression?.statements?.size | ||
| if (size == null || size <= 1) return | ||
| val size = lambdaExpression.collectDescendantsOfType<KtBlockExpression>().flatMap { it.statements }.size |
There was a problem hiding this comment.
@t-kameyama thanks for the quick fix!
Small note: unnecessary creation of intermediate list...
val size = lambdaExpression.collectDescendantsOfType<KtBlockExpression>().sumOf { it.statements.size }
looks like we could have a UseSumInsteadOfSize similar to UseAnyOrNoneInsteadOfFind, I'll open an issue.
|
Would this change have caused the following to trigger MultilineLambdaItParameter: If yes, I'd argue that I want to keep that as edit Another example: |
|
Example 1 is covered in #5504 Example 2: I agree that this is simple enough (more on this later), but I guess maybe the rule needs to be smarter, and either consider this style as a "single line", or detect that the receiver is a simple name. Because it might as well be @Test
fun `example2`() {
val code = """
interface TextView {
var isVisible: Boolean
var text: String
}
fun phrase(text: String, b1: Boolean, b2: Boolean, block: () -> String?): String = TODO()
fun f(textView: TextView, text: String?) {
textView.isVisible = text?.also {
textView.text = phrase(it, false, false) { null }
} != null
}
""".trimIndent()
val findings = subject.compileAndLintWithContext(env, code)
assertThat(findings).isEmpty()
}Now, as for "simple enough". I strongly believe that when a Detekt (or any inspection / static analysis tool) flags a line of code, it is for a reason. But we should never take the suggestions literally as the rules are rules, but the solution might be something totally different. For example in your second example, it took me about a 30 seconds to decypher the data flow and nullabilities, which is unnecessarily long. The code could be way simpler: val somekindOfPhrase = phrase(text, false, false) { null } // name based on those (false, false, null) behavior flags
textView.isVisible = somekindOfPhrase != null
textView.text = somekindOfPhraseok, this is not a single statement, but we don't need to take "in Kotlin, everything is an expression" literally, right? 🤓 Note that the two textView.textOrGone = phrase(text, false, false) { null } |
I strongly agree! In fact, I hate this snippet of code, and we did eventually make something like #5503 is a generalization of this (and I like my example there better), but this one was failing due to this PR so I included it here. |
Fixes #5393