From 02ddc0782ae16e72c037e488bdafa20165176407 Mon Sep 17 00:00:00 2001 From: nickreid Date: Mon, 15 Apr 2024 09:50:50 -0700 Subject: [PATCH] Emit a parsing error for calls with multiple trailing lambdas --- .../ktfmt/format/KotlinInputAstVisitor.kt | 18 +++++++++------ .../com/facebook/ktfmt/format/ParseError.kt | 22 +++++++++++++++++-- .../java/com/facebook/ktfmt/cli/MainTest.kt | 12 ++++++++++ 3 files changed, 43 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/com/facebook/ktfmt/format/KotlinInputAstVisitor.kt b/core/src/main/java/com/facebook/ktfmt/format/KotlinInputAstVisitor.kt index b233074f..da62912e 100644 --- a/core/src/main/java/com/facebook/ktfmt/format/KotlinInputAstVisitor.kt +++ b/core/src/main/java/com/facebook/ktfmt/format/KotlinInputAstVisitor.kt @@ -771,13 +771,17 @@ class KotlinInputAstVisitor( } } } - if (lambdaArguments.isNotEmpty()) { - builder.space() - visitArgumentInternal( - lambdaArguments.single(), - wrapInBlock = false, - brokeBeforeBrace = brokeBeforeBrace, - ) + when (lambdaArguments.size) { + 0 -> {} + 1 -> { + builder.space() + visitArgumentInternal( + lambdaArguments.single(), + wrapInBlock = false, + brokeBeforeBrace = brokeBeforeBrace, + ) + } + else -> throw ParseError("Maximum one trailing lambda is allowed", lambdaArguments[1]) } } } diff --git a/core/src/main/java/com/facebook/ktfmt/format/ParseError.kt b/core/src/main/java/com/facebook/ktfmt/format/ParseError.kt index 216dfb6a..b116e210 100644 --- a/core/src/main/java/com/facebook/ktfmt/format/ParseError.kt +++ b/core/src/main/java/com/facebook/ktfmt/format/ParseError.kt @@ -17,7 +17,25 @@ package com.facebook.ktfmt.format import org.jetbrains.kotlin.com.intellij.openapi.util.text.LineColumn +import org.jetbrains.kotlin.com.intellij.psi.PsiElement class ParseError(val errorDescription: String, val lineColumn: LineColumn) : - IllegalArgumentException( - "${lineColumn.line + 1}:${lineColumn.column + 1}: error: $errorDescription") + IllegalArgumentException( + "${lineColumn.line + 1}:${lineColumn.column + 1}: error: $errorDescription" + ) { + + constructor( + errorDescription: String, + element: PsiElement, + ) : this(errorDescription, positionOf(element)) + + companion object { + private fun positionOf(element: PsiElement): LineColumn { + val doc = element.containingFile.viewProvider.document + val offset = element.textOffset + val lineZero = doc.getLineNumber(offset) + val colZero = offset - doc.getLineStartOffset(lineZero) + return LineColumn.of(lineZero, colZero) + } + } +} diff --git a/core/src/test/java/com/facebook/ktfmt/cli/MainTest.kt b/core/src/test/java/com/facebook/ktfmt/cli/MainTest.kt index 6e207fe7..925ad271 100644 --- a/core/src/test/java/com/facebook/ktfmt/cli/MainTest.kt +++ b/core/src/test/java/com/facebook/ktfmt/cli/MainTest.kt @@ -159,6 +159,18 @@ class MainTest { assertThat(err.toString(testCharset)).contains("foo.kt:1:14: error: ") } + @Test + fun `Parsing error for multiple trailing lambdas`() { + val fooBar = root.resolve("foo.kt") + fooBar.writeText("val x = foo(bar { } { zap = 2 })") + val returnValue = + Main(emptyInput, PrintStream(out), PrintStream(err), arrayOf(fooBar.toString())).run() + + assertThat(returnValue).isEqualTo(1) + assertThat(err.toString(testCharset)) + .contains("foo.kt:1:21: error: Maximum one trailing lambda is allowed") + } + @Test fun `all files in args are processed, even if one of them has an error`() { val file1 = root.resolve("file1.kt")