diff --git a/compiler/psi/src/org/jetbrains/kotlin/psi/psiUtil/ktPsiUtil.kt b/compiler/psi/src/org/jetbrains/kotlin/psi/psiUtil/ktPsiUtil.kt index 58e323502aa..a3e2cbfb49d 100644 --- a/compiler/psi/src/org/jetbrains/kotlin/psi/psiUtil/ktPsiUtil.kt +++ b/compiler/psi/src/org/jetbrains/kotlin/psi/psiUtil/ktPsiUtil.kt @@ -681,5 +681,6 @@ fun getTrailingCommaByClosingElement(closingElement: PsiElement?): PsiElement? { } fun getTrailingCommaByElementsList(elementList: PsiElement?): PsiElement? { - return elementList?.lastChild?.run { if (node.elementType == KtTokens.COMMA) this else null } + val lastChild = elementList?.lastChild?.let { if (it !is PsiComment) it else it.getPrevSiblingIgnoringWhitespaceAndComments() } + return lastChild?.run { if (node.elementType == KtTokens.COMMA) this else null } } diff --git a/idea/formatter/src/org/jetbrains/kotlin/idea/formatter/KotlinCommonBlock.kt b/idea/formatter/src/org/jetbrains/kotlin/idea/formatter/KotlinCommonBlock.kt index 411af9aa07e..950dc4a977d 100644 --- a/idea/formatter/src/org/jetbrains/kotlin/idea/formatter/KotlinCommonBlock.kt +++ b/idea/formatter/src/org/jetbrains/kotlin/idea/formatter/KotlinCommonBlock.kt @@ -8,7 +8,6 @@ package org.jetbrains.kotlin.idea.formatter import com.intellij.formatting.* import com.intellij.lang.ASTNode import com.intellij.openapi.util.TextRange -import com.intellij.openapi.util.text.StringUtil import com.intellij.psi.PsiComment import com.intellij.psi.PsiElement import com.intellij.psi.TokenType @@ -20,13 +19,16 @@ import com.intellij.psi.tree.TokenSet import org.jetbrains.kotlin.KtNodeTypes.* import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings import org.jetbrains.kotlin.idea.formatter.NodeIndentStrategy.Companion.strategy +import org.jetbrains.kotlin.idea.util.containsLineBreakInThis import org.jetbrains.kotlin.idea.util.isMultiline +import org.jetbrains.kotlin.idea.util.needTrailingComma import org.jetbrains.kotlin.idea.util.requireNode import org.jetbrains.kotlin.kdoc.lexer.KDocTokens import org.jetbrains.kotlin.kdoc.parser.KDocElementTypes import org.jetbrains.kotlin.lexer.KtTokens.* import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.* +import org.jetbrains.kotlin.utils.addToStdlib.cast import org.jetbrains.kotlin.utils.addToStdlib.safeAs private val QUALIFIED_OPERATION = TokenSet.create(DOT, SAFE_ACCESS) @@ -600,15 +602,31 @@ abstract class KotlinCommonBlock( } elementType === VALUE_PARAMETER_LIST -> { - if (parentElementType === FUN || - parentElementType === PRIMARY_CONSTRUCTOR || - parentElementType === SECONDARY_CONSTRUCTOR - ) return getWrappingStrategyForItemList( - commonSettings.METHOD_PARAMETERS_WRAP, - VALUE_PARAMETER, - node.withTrailingComma, - additionalWrap = trailingCommaWrappingStrategyWithMultiLineCheck(LPAR, RPAR) - ) + when (parentElementType) { + FUN, PRIMARY_CONSTRUCTOR, SECONDARY_CONSTRUCTOR -> return getWrappingStrategyForItemList( + commonSettings.METHOD_PARAMETERS_WRAP, + VALUE_PARAMETER, + node.withTrailingComma, + additionalWrap = trailingCommaWrappingStrategyWithMultiLineCheck(LPAR, RPAR) + ) + FUNCTION_LITERAL -> { + if (nodePsi.parent?.safeAs()?.needTrailingComma(settings) == true) { + val check = thisOrPrevIsMultiLineElement(COMMA, LBRACE /* not necessary */, ARROW /* not necessary */) + return { childElement -> + createWrapAlwaysIf(getPrevWithoutWhitespaceAndComments(childElement) == null || check(childElement)) + } + } + } + } + } + + elementType === FUNCTION_LITERAL -> { + val withTrailingComma = nodePsi.cast().needTrailingComma(settings) + return { childElement -> + createWrapAlwaysIf( + withTrailingComma && (childElement.elementType === ARROW || getPrevWithoutWhitespaceAndComments(childElement)?.elementType === LBRACE) + ) + } } elementType === INDICES -> return defaultTrailingCommaWrappingStrategy(LBRACKET, RBRACKET) @@ -676,8 +694,7 @@ abstract class KotlinCommonBlock( nodePsi is KtProperty -> return wrap@{ childElement -> - val wrapSetting = - if (nodePsi.isLocal) commonSettings.VARIABLE_ANNOTATION_WRAP else commonSettings.FIELD_ANNOTATION_WRAP + val wrapSetting = if (nodePsi.isLocal) commonSettings.VARIABLE_ANNOTATION_WRAP else commonSettings.FIELD_ANNOTATION_WRAP getWrapAfterAnnotation(childElement, wrapSetting)?.let { return@wrap it } @@ -763,9 +780,7 @@ abstract class KotlinCommonBlock( val startOffset = childElement.notDelimiterSiblingNodeInSequence(false, delimiterType, leftBarrier)?.startOffset ?: psi.startOffset val endOffset = childElement.notDelimiterSiblingNodeInSequence(true, delimiterType, rightBarrier)?.psi?.endOffset ?: psi.endOffset - val treeParent = childElement.treeParent - val textRange = TextRange.create(startOffset, endOffset).shiftLeft(treeParent.startOffset) - return StringUtil.containsLineBreak(textRange.subSequence(treeParent.text)) + return psi.parent.containsLineBreakInThis(startOffset, endOffset) } private fun trailingCommaWrappingStrategyWithMultiLineCheck( @@ -779,14 +794,12 @@ abstract class KotlinCommonBlock( additionalCheck: (ASTNode) -> Boolean ): WrappingStrategy = { childElement -> val childElementType = childElement.elementType - if (childElement.treeParent.withTrailingComma && (childElementType === rightAnchor || + createWrapAlwaysIf( + childElement.treeParent.withTrailingComma && (childElementType === rightAnchor || getPrevWithoutWhitespaceAndComments(childElement)?.elementType === leftAnchor || additionalCheck(childElement) ) ) - Wrap.createWrap(WrapType.ALWAYS, true) - else - null } } @@ -1139,3 +1152,5 @@ private fun extractIndent(node: ASTNode): String { return "" return prevNode.text.substringAfterLast("\n", prevNode.text) } + +private fun createWrapAlwaysIf(option: Boolean): Wrap? = if (option) Wrap.createWrap(WrapType.ALWAYS, true) else null \ No newline at end of file diff --git a/idea/formatter/src/org/jetbrains/kotlin/idea/util/FormatterUtil.kt b/idea/formatter/src/org/jetbrains/kotlin/idea/util/FormatterUtil.kt index 2a0b5f757fa..d9a38cde03e 100644 --- a/idea/formatter/src/org/jetbrains/kotlin/idea/util/FormatterUtil.kt +++ b/idea/formatter/src/org/jetbrains/kotlin/idea/util/FormatterUtil.kt @@ -10,7 +10,12 @@ import com.intellij.openapi.util.TextRange import com.intellij.openapi.util.text.StringUtil import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiElement +import com.intellij.psi.codeStyle.CodeStyleSettings import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings +import org.jetbrains.kotlin.idea.formatter.kotlinCustomSettings +import org.jetbrains.kotlin.psi.KtFunctionLiteral +import org.jetbrains.kotlin.psi.psiUtil.endOffset +import org.jetbrains.kotlin.psi.psiUtil.startOffset /* * ASTBlock.node is nullable, this extension was introduced to minimize changes @@ -39,3 +44,16 @@ fun PsiElement.getLineCount(): Int { } fun PsiElement.isMultiline() = getLineCount() > 1 + +fun KtFunctionLiteral.needTrailingComma(settings: CodeStyleSettings): Boolean = valueParameterList?.trailingComma != null || + settings.kotlinCustomSettings.ALLOW_TRAILING_COMMA && + run(fun(): Boolean { + val startOffset = valueParameterList?.startOffset ?: return false + val endOffset = arrow?.endOffset ?: return false + return containsLineBreakInThis(startOffset, endOffset) + }) + +fun PsiElement.containsLineBreakInThis(globalStartOffset: Int, globalEndOffset: Int): Boolean { + val textRange = TextRange.create(globalStartOffset, globalEndOffset).shiftLeft(startOffset) + return StringUtil.containsLineBreak(textRange.subSequence(text)) +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/formatter/TrailingCommaPostFormatProcessor.kt b/idea/src/org/jetbrains/kotlin/idea/formatter/TrailingCommaPostFormatProcessor.kt index 0f2b3611d76..c809e51eaea 100644 --- a/idea/src/org/jetbrains/kotlin/idea/formatter/TrailingCommaPostFormatProcessor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/formatter/TrailingCommaPostFormatProcessor.kt @@ -15,6 +15,7 @@ import com.intellij.psi.codeStyle.CodeStyleSettings import com.intellij.psi.impl.source.codeStyle.PostFormatProcessor import com.intellij.psi.impl.source.codeStyle.PostFormatProcessorHelper import org.jetbrains.kotlin.idea.util.isMultiline +import org.jetbrains.kotlin.idea.util.needTrailingComma import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer @@ -66,13 +67,13 @@ private class TrailingCommaVisitor(val settings: CodeStyleSettings) : KtTreeVisi } private fun processCommaOwner(parent: KtElement) { - val previous = parent.lastChild?.getPrevSiblingIgnoringWhitespaceAndComments() ?: return - val elementType = previous.safeAs()?.elementType - if (elementType === KtTokens.COMMA || settings.kotlinCustomSettings.ALLOW_TRAILING_COMMA && parent.isMultiline()) { + val lastElement = parent.lastCommaOwnerOrComma ?: return + val elementType = lastElement.safeAs()?.elementType + if (elementType === KtTokens.COMMA || parent.needComma) { // add a missing comma if (elementType !== KtTokens.COMMA) { changePsi(parent) { element, factory -> - element.addAfter(factory.createComma(), previous) + element.addAfter(factory.createComma(), lastElement) } } @@ -80,6 +81,12 @@ private class TrailingCommaVisitor(val settings: CodeStyleSettings) : KtTreeVisi } } + private val KtElement.needComma: Boolean + get() = when (val parent = parent) { + is KtFunctionLiteral -> parent.needTrailingComma(settings) + else -> settings.kotlinCustomSettings.ALLOW_TRAILING_COMMA && isMultiline() + } + private fun changePsi(element: KtElement, update: (KtElement, KtPsiFactory) -> Unit) { val oldLength = element.textLength update(element, KtPsiFactory(element)) @@ -88,9 +95,7 @@ private class TrailingCommaVisitor(val settings: CodeStyleSettings) : KtTreeVisi } private fun correctCommaPosition(parent: KtElement) { - val lPar = parent.children.firstOrNull() ?: return - val rPar = parent.children.lastOrNull() ?: return - val invalidElements = lPar.siblings(withItself = false).takeWhile { it != rPar }.mapNotNull { + val invalidElements = parent.firstChild?.siblings(withItself = false)?.mapNotNull { if (it !is ASTNode || it.elementType != KtTokens.COMMA) return@mapNotNull null val prevWithComment = it.getPrevSiblingIgnoringWhitespace(false) @@ -99,7 +104,7 @@ private class TrailingCommaVisitor(val settings: CodeStyleSettings) : KtTreeVisi it.createSmartPointer() to prevWithoutComment.createSmartPointer() } else null - }.toList() + }?.toList() ?: return if (invalidElements.isNotEmpty()) { changePsi(parent) { element, factory -> @@ -129,4 +134,16 @@ private class TrailingCommaVisitor(val settings: CodeStyleSettings) : KtTreeVisi companion object { private val LOG = Logger.getInstance(TrailingCommaVisitor::class.java) } -} \ No newline at end of file +} + +private val PsiElement.lastCommaOwnerOrComma: PsiElement? + get() { + val lastChild = lastChild ?: return null + val withSelf = when (lastChild.safeAs()?.elementType) { + KtTokens.COMMA -> return lastChild + KtTokens.RBRACKET, KtTokens.RPAR, KtTokens.RBRACE, KtTokens.GT -> false + else -> true + } + + return lastChild.getPrevSiblingIgnoringWhitespaceAndComments(withSelf) + } diff --git a/idea/testData/formatter/trailingComma/collectionLiteralExpression/CollectionLiteralInAnnotation.after.inv.kt b/idea/testData/formatter/trailingComma/collectionLiteralExpression/CollectionLiteralInAnnotation.after.inv.kt index 3d389d5964d..e94bc3b5915 100644 --- a/idea/testData/formatter/trailingComma/collectionLiteralExpression/CollectionLiteralInAnnotation.after.inv.kt +++ b/idea/testData/formatter/trailingComma/collectionLiteralExpression/CollectionLiteralInAnnotation.after.inv.kt @@ -97,8 +97,8 @@ fun a() = Unit @Anno([ 1, - 2/* - */,/* + 2,/* + *//* */ ]) fun a() = Unit diff --git a/idea/testData/formatter/trailingComma/collectionLiteralExpression/CollectionLiteralInAnnotation.after.kt b/idea/testData/formatter/trailingComma/collectionLiteralExpression/CollectionLiteralInAnnotation.after.kt index 1071b7e82db..467ad2d0512 100644 --- a/idea/testData/formatter/trailingComma/collectionLiteralExpression/CollectionLiteralInAnnotation.after.kt +++ b/idea/testData/formatter/trailingComma/collectionLiteralExpression/CollectionLiteralInAnnotation.after.kt @@ -148,8 +148,8 @@ fun a() = Unit @Anno( [ 1, - 2/* - */,/* + 2,/* + *//* */ ], ) diff --git a/idea/testData/formatter/trailingComma/lambdaParameters/LambdaParameterList.after.inv.kt b/idea/testData/formatter/trailingComma/lambdaParameters/LambdaParameterList.after.inv.kt new file mode 100644 index 00000000000..990b3979b38 --- /dev/null +++ b/idea/testData/formatter/trailingComma/lambdaParameters/LambdaParameterList.after.inv.kt @@ -0,0 +1,190 @@ +val x = { + x: Comparable>, + y: String, + -> + println("1") +} + +val x = { x: Comparable>, y: String -> + println("1") +} + +val x = { x: String, y +: String -> + println("1") +} + +val x = { x: String, + y: String + -> + println("1") +} + +val x = { + x: String, + y: Comparable>, + -> + println("1") +} + +val x = { + x: Comparable>, + y: String, + -> + println("1") +} + +val x = { + x: String, + y: Comparable>, + z: String, + -> + println("1") +} + +val x = { x: String, + y: String, + z: String + -> + println("1") +} + +val x = { + x: String, + y: String, + z: String, + -> + println("1") +} + +val x = { + x: String, + y: String, + z: String, + -> + println("1") +} + +val x = { + x: String, + -> + println("1") +} + +val x = { x: String + -> + println("1") +} + +val x = { + x: String, + -> + println("1") +} + +val x = { + x: String, + -> + println("1") +} + +val x = { + x: String, + y: String, + -> + println("1") +} + +val x = { x: String, + z: String + -> + println("1") +} + +val x = { + x: String, + y: String, + z: String, + -> + println("1") +} + +val x = { + x: String, + z: String, + -> + println("1") +} + +val x = { + x, y: String, + z: String, + -> + println("1") +} + +val x = { x: String, y: String, z: String + -> + println("1") +} + +val x = { + z: String, v: Comparable>, + + -> + println("1") +} + +val x = { + x: String, + y: Comparable>, + -> + println("1") +} + +val x = { x: Int + -> + println("1") +} + +val x = { x: String, y: String, /* */ z: String + -> + println("1") +} + +val x = { x: String, y: String + /* */, /* */ z: String + -> + println("1") +}() + +val x = { + x: String, /* + */ + y: String, + z: String, + -> + println("1") +} + +val x = { + x: String, y: String, + z: String, /* + */ + -> + println("1") +} + +val x = { + x: Comparable>, y: String, + z: String, + -> + println("1") +} + +val x = { x: String, y: String, z: String + -> + println("1") +} + +// SET_TRUE: ALLOW_TRAILING_COMMA diff --git a/idea/testData/formatter/trailingComma/lambdaParameters/LambdaParameterList.after.kt b/idea/testData/formatter/trailingComma/lambdaParameters/LambdaParameterList.after.kt new file mode 100644 index 00000000000..35c8b8af142 --- /dev/null +++ b/idea/testData/formatter/trailingComma/lambdaParameters/LambdaParameterList.after.kt @@ -0,0 +1,205 @@ +val x = { + x: Comparable>, + y: String, + -> + println("1") +} + +val x = { x: Comparable>, y: String -> + println("1") +} + +val x = { + x: String, + y + : String, + -> + println("1") +} + +val x = { + x: String, + y: String, + -> + println("1") +} + +val x = { + x: String, + y: Comparable>, + -> + println("1") +} + +val x = { + x: Comparable>, + y: String, + -> + println("1") +} + +val x = { + x: String, + y: Comparable>, + z: String, + -> + println("1") +} + +val x = { + x: String, + y: String, + z: String, + -> + println("1") +} + +val x = { + x: String, + y: String, + z: String, + -> + println("1") +} + +val x = { + x: String, + y: String, + z: String, + -> + println("1") +} + +val x = { + x: String, + -> + println("1") +} + +val x = { + x: String, + -> + println("1") +} + +val x = { + x: String, + -> + println("1") +} + +val x = { + x: String, + -> + println("1") +} + +val x = { + x: String, + y: String, + -> + println("1") +} + +val x = { + x: String, + z: String, + -> + println("1") +} + +val x = { + x: String, + y: String, + z: String, + -> + println("1") +} + +val x = { + x: String, + z: String, + -> + println("1") +} + +val x = { + x, y: String, + z: String, + -> + println("1") +} + +val x = { + x: String, y: String, z: String, + -> + println("1") +} + +val x = { + z: String, v: Comparable>, + + -> + println("1") +} + +val x = { + x: String, + y: Comparable>, + -> + println("1") +} + +val x = { + x: Int, + -> + println("1") +} + +val x = { + x: String, y: String, /* */ + z: String, + -> + println("1") +} + +val x = { + x: String, + y: String, + /* */ /* */ + z: String, + -> + println("1") +}() + +val x = { + x: String, /* + */ + y: String, + z: String, + -> + println("1") +} + +val x = { + x: String, y: String, + z: String, /* + */ + -> + println("1") +} + +val x = { + x: Comparable>, y: String, + z: String, + -> + println("1") +} + +val x = { + x: String, y: String, z: String, + -> + println("1") +} + +// SET_TRUE: ALLOW_TRAILING_COMMA diff --git a/idea/testData/formatter/trailingComma/lambdaParameters/LambdaParameterList.kt b/idea/testData/formatter/trailingComma/lambdaParameters/LambdaParameterList.kt new file mode 100644 index 00000000000..ee10136f1e9 --- /dev/null +++ b/idea/testData/formatter/trailingComma/lambdaParameters/LambdaParameterList.kt @@ -0,0 +1,192 @@ +val x = { + x: Comparable>, + y: String, +-> + println("1") + } + +val x = {x: Comparable>, y: String-> + println("1") + } + +val x = {x: String, y +: String-> + println("1") + } + +val x = { + x: String, + y: String +-> + println("1") + } + +val x = { + x: String, + y: Comparable>,-> + println("1") + } + +val x = { + x: Comparable>, + y: String + ,-> + println("1") + } + +val x = { + x: String, + y: Comparable>, + z: String, +-> + println("1") + } + +val x = { + x: String, + y: String, + z: String +-> + println("1") + } + +val x = { + x: String, + y: String, + z: String,-> + println("1") + } + +val x = { + x: String, + y: String, + z: String + ,-> + println("1") + } + +val x = { + x: String, +-> + println("1") + } + +val x = { + x: String +-> + println("1") + } + +val x = { + x: String,-> + println("1") + } + +val x = { + x: String + ,-> + println("1") + } + +val x = { + x: String , + y: String, +-> + println("1") + } + +val x = { + x: String, + z: String +-> + println("1") + } + +val x = { + x: String, + y: String, + z: String ,-> + println("1") + } + +val x = { + x: String, + z: String + , -> + println("1") + } + +val x = { + x, y: String, + z: String + , -> + println("1") + } + +val x = { + x: String, y: String, z: String +-> + println("1") + } + +val x = { + z: String, v: Comparable>, + +-> + println("1") + } + +val x = {x: String, + y: Comparable>, +-> + println("1") + } + +val x = { + x: Int +-> + println("1") + } + +val x = { + x: String, y: String + , /* */ z: String +-> + println("1") + } + +val x = { + x: String, y: String + /* */, /* */ z: String +-> + println("1") + }() + +val x = { + x: String, /* + */ y: String, + z: String ,-> + println("1") + } + +val x = { + x: String, y: String , z: String /* + */ + , -> + println("1") + } + +val x = { + x: Comparable>, y: String, + z: String + , -> + println("1") + } + +val x = { + x: String, y: String, z: String +-> + println("1") + } + +// SET_TRUE: ALLOW_TRAILING_COMMA diff --git a/idea/testData/formatter/trailingComma/typeParameters/TypeParameterList.after.inv.kt b/idea/testData/formatter/trailingComma/typeParameters/TypeParameterList.after.inv.kt index a5fb3abb4ae..978e83bd1c8 100644 --- a/idea/testData/formatter/trailingComma/typeParameters/TypeParameterList.after.inv.kt +++ b/idea/testData/formatter/trailingComma/typeParameters/TypeParameterList.after.inv.kt @@ -226,8 +226,8 @@ class H< class J< x : String, y : String, - z : String /* - */, + z : String, /* + */ > class K< diff --git a/idea/testData/formatter/trailingComma/typeParameters/TypeParameterList.after.kt b/idea/testData/formatter/trailingComma/typeParameters/TypeParameterList.after.kt index 6b945282451..5d046fbd76c 100644 --- a/idea/testData/formatter/trailingComma/typeParameters/TypeParameterList.after.kt +++ b/idea/testData/formatter/trailingComma/typeParameters/TypeParameterList.after.kt @@ -234,8 +234,8 @@ class H< class J< x : String, y : String, - z : String /* - */, + z : String, /* + */ > class K< diff --git a/idea/tests/org/jetbrains/kotlin/formatter/FormatterTestGenerated.java b/idea/tests/org/jetbrains/kotlin/formatter/FormatterTestGenerated.java index 6745d9e8b13..79adc558ca5 100644 --- a/idea/tests/org/jetbrains/kotlin/formatter/FormatterTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/formatter/FormatterTestGenerated.java @@ -1200,6 +1200,24 @@ public class FormatterTestGenerated extends AbstractFormatterTest { } } + @TestMetadata("idea/testData/formatter/trailingComma/lambdaParameters") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class LambdaParameters extends AbstractFormatterTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInLambdaParameters() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/formatter/trailingComma/lambdaParameters"), Pattern.compile("^([^\\.]+)\\.after\\.kt.*$"), null, true); + } + + @TestMetadata("LambdaParameterList.after.kt") + public void testLambdaParameterList() throws Exception { + runTest("idea/testData/formatter/trailingComma/lambdaParameters/LambdaParameterList.after.kt"); + } + } + @TestMetadata("idea/testData/formatter/trailingComma/typeArguments") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -1716,6 +1734,24 @@ public class FormatterTestGenerated extends AbstractFormatterTest { } } + @TestMetadata("idea/testData/formatter/trailingComma/lambdaParameters") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class LambdaParameters extends AbstractFormatterTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTestInverted, this, testDataFilePath); + } + + public void testAllFilesPresentInLambdaParameters() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/formatter/trailingComma/lambdaParameters"), Pattern.compile("^([^\\.]+)\\.after\\.inv\\.kt.*$"), null, true); + } + + @TestMetadata("LambdaParameterList.after.inv.kt") + public void testLambdaParameterList() throws Exception { + runTest("idea/testData/formatter/trailingComma/lambdaParameters/LambdaParameterList.after.inv.kt"); + } + } + @TestMetadata("idea/testData/formatter/trailingComma/typeArguments") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)