diff --git a/idea/formatter/src/org/jetbrains/kotlin/idea/core/formatter/KotlinCodeStyleSettings.java b/idea/formatter/src/org/jetbrains/kotlin/idea/core/formatter/KotlinCodeStyleSettings.java
index 3fcae996b7f..b6ee014a3e4 100644
--- a/idea/formatter/src/org/jetbrains/kotlin/idea/core/formatter/KotlinCodeStyleSettings.java
+++ b/idea/formatter/src/org/jetbrains/kotlin/idea/core/formatter/KotlinCodeStyleSettings.java
@@ -11,7 +11,10 @@ import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.WriteExternalException;
-import com.intellij.psi.codeStyle.*;
+import com.intellij.psi.codeStyle.CodeStyleSettings;
+import com.intellij.psi.codeStyle.CustomCodeStyleSettings;
+import com.intellij.psi.codeStyle.PackageEntry;
+import com.intellij.psi.codeStyle.PackageEntryTable;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -50,6 +53,7 @@ public class KotlinCodeStyleSettings extends CustomCodeStyleSettings {
public int WRAP_EXPRESSION_BODY_FUNCTIONS = 0;
public int WRAP_ELVIS_EXPRESSIONS = 1;
public boolean IF_RPAREN_ON_NEW_LINE = false;
+ public boolean ALLOW_TRAILING_COMMA = true;
@ReflectionUtil.SkipInEquals
public String CODE_STYLE_DEFAULTS = 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 9ab8c9e0d40..be206a67187 100644
--- a/idea/formatter/src/org/jetbrains/kotlin/idea/formatter/KotlinCommonBlock.kt
+++ b/idea/formatter/src/org/jetbrains/kotlin/idea/formatter/KotlinCommonBlock.kt
@@ -19,6 +19,7 @@ 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.getLineCount
import org.jetbrains.kotlin.idea.util.requireNode
import org.jetbrains.kotlin.kdoc.lexer.KDocTokens
import org.jetbrains.kotlin.kdoc.parser.KDocElementTypes
@@ -598,7 +599,14 @@ abstract class KotlinCommonBlock(
parentElementType === SECONDARY_CONSTRUCTOR
) {
val wrap = Wrap.createWrap(commonSettings.METHOD_PARAMETERS_WRAP, false)
- return { childElement -> wrap.takeIf { childElement.elementType === VALUE_PARAMETER } }
+ val withTrailingComma = node.withTrailingComma
+ return { childElement ->
+ val childElementType = childElement.elementType
+ if (withTrailingComma && (childElementType === RPAR || getPrevWithoutWhitespaceAndComments(childElement)?.elementType === LPAR))
+ Wrap.createWrap(WrapType.ALWAYS, true)
+ else
+ wrap.takeIf { childElementType === VALUE_PARAMETER }
+ }
}
}
@@ -698,6 +706,13 @@ abstract class KotlinCommonBlock(
return ::noWrapping
}
+
+ private val ASTNode.withTrailingComma: Boolean
+ get() = when {
+ lastChildNode?.let { getPrevWithoutWhitespaceAndComments(it) }?.elementType === COMMA -> true
+ settings.kotlinCustomSettings.ALLOW_TRAILING_COMMA -> psi?.getLineCount()?.let { it > 1 } == true
+ else -> false
+ }
}
private fun ASTNode.isFirstParameter(): Boolean = treePrev?.elementType == LPAR
diff --git a/idea/formatter/src/org/jetbrains/kotlin/idea/formatter/kotlinSpacingRules.kt b/idea/formatter/src/org/jetbrains/kotlin/idea/formatter/kotlinSpacingRules.kt
index 969cec7cc12..2ea040d7e67 100644
--- a/idea/formatter/src/org/jetbrains/kotlin/idea/formatter/kotlinSpacingRules.kt
+++ b/idea/formatter/src/org/jetbrains/kotlin/idea/formatter/kotlinSpacingRules.kt
@@ -271,10 +271,9 @@ fun createSpacingBuilder(settings: CodeStyleSettings, builderUtil: KotlinSpacing
after(DOC_COMMENT).lineBreakInCode()
// =============== Spacing ================
- before(COMMA).spaceIf(kotlinCommonSettings.SPACE_BEFORE_COMMA)
+ before(COMMA).spacesNoLineBreak(if (kotlinCommonSettings.SPACE_BEFORE_COMMA) 1 else 0)
after(COMMA).spaceIf(kotlinCommonSettings.SPACE_AFTER_COMMA)
-
val spacesAroundAssignment = if (kotlinCommonSettings.SPACE_AROUND_ASSIGNMENT_OPERATORS) 1 else 0
beforeInside(EQ, PROPERTY).spacesNoLineBreak(spacesAroundAssignment)
beforeInside(EQ, FUN).spacing(spacesAroundAssignment, spacesAroundAssignment, 0, false, 0)
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 d736a949be7..ef50dab458e 100644
--- a/idea/formatter/src/org/jetbrains/kotlin/idea/util/FormatterUtil.kt
+++ b/idea/formatter/src/org/jetbrains/kotlin/idea/util/FormatterUtil.kt
@@ -1,11 +1,15 @@
/*
- * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.util
import com.intellij.formatting.ASTBlock
+import com.intellij.openapi.util.TextRange
+import com.intellij.openapi.util.text.StringUtil
+import com.intellij.psi.PsiDocumentManager
+import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
/*
@@ -16,4 +20,20 @@ fun ASTBlock.requireNode() = node ?: error("ASTBlock.getNode() returned null")
/**
* Can be removed with all usages after moving master to 1.3 with new default code style settings.
*/
-val isDefaultOfficialCodeStyle by lazy { !KotlinCodeStyleSettings.defaultSettings().CONTINUATION_INDENT_FOR_CHAINED_CALLS }
\ No newline at end of file
+val isDefaultOfficialCodeStyle by lazy { !KotlinCodeStyleSettings.defaultSettings().CONTINUATION_INDENT_FOR_CHAINED_CALLS }
+
+fun PsiElement.getLineCount(): Int {
+ val doc = containingFile?.let { file -> file.viewProvider.document ?: PsiDocumentManager.getInstance(project).getDocument(file) }
+ if (doc != null) {
+ val spaceRange = textRange ?: TextRange.EMPTY_RANGE
+
+ if (spaceRange.endOffset <= doc.textLength) {
+ val startLine = doc.getLineNumber(spaceRange.startOffset)
+ val endLine = doc.getLineNumber(spaceRange.endOffset)
+
+ return endLine - startLine + 1
+ }
+ }
+
+ return StringUtil.getLineBreakCount(text ?: "") + 1
+}
\ No newline at end of file
diff --git a/idea/resources/META-INF/plugin-common.xml b/idea/resources/META-INF/plugin-common.xml
index 956a5cdcb34..ec428fa5e39 100644
--- a/idea/resources/META-INF/plugin-common.xml
+++ b/idea/resources/META-INF/plugin-common.xml
@@ -430,6 +430,7 @@
+
diff --git a/idea/src/org/jetbrains/kotlin/idea/formatter/KotlinLanguageCodeStyleSettingsProvider.kt b/idea/src/org/jetbrains/kotlin/idea/formatter/KotlinLanguageCodeStyleSettingsProvider.kt
index f3a3f055842..c762b44f710 100644
--- a/idea/src/org/jetbrains/kotlin/idea/formatter/KotlinLanguageCodeStyleSettingsProvider.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/formatter/KotlinLanguageCodeStyleSettingsProvider.kt
@@ -1,5 +1,5 @@
/*
- * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@@ -293,6 +293,8 @@ class KotlinLanguageCodeStyleSettingsProvider : LanguageCodeStyleSettingsProvide
consumer.renameStandardOption("METHOD_ANNOTATION_WRAP", "Function annotations")
consumer.renameStandardOption(CodeStyleSettingsCustomizable.WRAPPING_METHOD_PARENTHESES, "Function parentheses")
+ showCustomOption(KotlinCodeStyleSettings::ALLOW_TRAILING_COMMA, "Use trailing comma")
+
showCustomOption(
KotlinCodeStyleSettings::ALIGN_IN_COLUMNS_CASE_BRANCH,
"Align 'when' branches in columns",
diff --git a/idea/src/org/jetbrains/kotlin/idea/formatter/TrailingCommaPostFormatProcessor.kt b/idea/src/org/jetbrains/kotlin/idea/formatter/TrailingCommaPostFormatProcessor.kt
new file mode 100644
index 00000000000..ba3cbf3786c
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/formatter/TrailingCommaPostFormatProcessor.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.idea.formatter
+
+import com.intellij.lang.ASTNode
+import com.intellij.openapi.diagnostic.Logger
+import com.intellij.openapi.util.TextRange
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiFile
+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.getLineCount
+import org.jetbrains.kotlin.lexer.KtTokens
+import org.jetbrains.kotlin.psi.KtElement
+import org.jetbrains.kotlin.psi.KtParameterList
+import org.jetbrains.kotlin.psi.KtPsiFactory
+import org.jetbrains.kotlin.psi.KtTreeVisitorVoid
+import org.jetbrains.kotlin.psi.psiUtil.getPrevSiblingIgnoringWhitespaceAndComments
+import org.jetbrains.kotlin.utils.addToStdlib.safeAs
+
+class TrailingCommaPostFormatProcessor : PostFormatProcessor {
+ override fun processElement(source: PsiElement, settings: CodeStyleSettings): PsiElement =
+ TrailingCommaVisitor(settings).process(source)
+
+ override fun processText(source: PsiFile, rangeToReformat: TextRange, settings: CodeStyleSettings): TextRange =
+ TrailingCommaVisitor(settings).processText(source, rangeToReformat)
+}
+
+private class TrailingCommaVisitor(val settings: CodeStyleSettings) : KtTreeVisitorVoid() {
+ private val myPostProcessor = PostFormatProcessorHelper(settings.kotlinCommonSettings)
+
+ override fun visitParameterList(list: KtParameterList) = processCommaOwnerIfInRange(list) {
+ super.visitParameterList(list)
+ }
+
+ private fun processCommaOwnerIfInRange(element: KtElement, preHook: () -> Unit = {}) {
+ if (myPostProcessor.isElementPartlyInRange(element)) {
+ preHook()
+ processCommaOwner(element)
+ }
+ }
+
+ private fun processCommaOwner(parent: KtElement) {
+ val previous = parent.lastChild?.getPrevSiblingIgnoringWhitespaceAndComments() ?: return
+ if (previous.safeAs()?.elementType !== KtTokens.COMMA &&
+ settings.kotlinCustomSettings.ALLOW_TRAILING_COMMA &&
+ parent.getLineCount() > 1
+ ) {
+ val oldLength = parent.textLength
+ parent.addAfter(KtPsiFactory(parent).createComma(), previous)
+ myPostProcessor.updateResultRange(oldLength, parent.textLength)
+ }
+ }
+
+ fun process(formatted: PsiElement): PsiElement {
+ LOG.assertTrue(formatted.isValid)
+ formatted.accept(this)
+ return formatted
+ }
+
+ fun processText(
+ source: PsiFile,
+ rangeToReformat: TextRange
+ ): TextRange {
+ myPostProcessor.resultTextRange = rangeToReformat
+ source.accept(this)
+ return myPostProcessor.resultTextRange
+ }
+
+ companion object {
+ private val LOG = Logger.getInstance(TrailingCommaVisitor::class.java)
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/formatter/BlankLinesAfterClassHeader.after.kt b/idea/testData/formatter/BlankLinesAfterClassHeader.after.kt
index d0575c00b7d..8ee4cf38681 100644
--- a/idea/testData/formatter/BlankLinesAfterClassHeader.after.kt
+++ b/idea/testData/formatter/BlankLinesAfterClassHeader.after.kt
@@ -19,7 +19,7 @@ class FooM
}
class FooC(
- val x: String
+ val x: String,
) {
fun bar()
diff --git a/idea/testData/formatter/ContinuationIndentInParameterLists.after.kt b/idea/testData/formatter/ContinuationIndentInParameterLists.after.kt
index 2c836d4db20..d031eb0def1 100644
--- a/idea/testData/formatter/ContinuationIndentInParameterLists.after.kt
+++ b/idea/testData/formatter/ContinuationIndentInParameterLists.after.kt
@@ -1,5 +1,5 @@
fun foo(
- x: Int
+ x: Int,
) {
}
diff --git a/idea/testData/formatter/FunctionDefParametersAlign.after.kt b/idea/testData/formatter/FunctionDefParametersAlign.after.kt
index 79a34d27d4c..8cddf45699a 100644
--- a/idea/testData/formatter/FunctionDefParametersAlign.after.kt
+++ b/idea/testData/formatter/FunctionDefParametersAlign.after.kt
@@ -1,3 +1,5 @@
fun test(a: Int,
b: Int) {
-}
\ No newline at end of file
+}
+
+// TRAILING_COMMA: false
\ No newline at end of file
diff --git a/idea/testData/formatter/FunctionDefParametersAlign.kt b/idea/testData/formatter/FunctionDefParametersAlign.kt
index 566e4de2d70..8754b18edcd 100644
--- a/idea/testData/formatter/FunctionDefParametersAlign.kt
+++ b/idea/testData/formatter/FunctionDefParametersAlign.kt
@@ -1,3 +1,5 @@
fun test(a : Int,
b : Int) {
-}
\ No newline at end of file
+}
+
+// TRAILING_COMMA: false
\ No newline at end of file
diff --git a/idea/testData/formatter/FunctionExpression.after.kt b/idea/testData/formatter/FunctionExpression.after.kt
index 3ee4ddcb10f..a70a38179eb 100644
--- a/idea/testData/formatter/FunctionExpression.after.kt
+++ b/idea/testData/formatter/FunctionExpression.after.kt
@@ -28,8 +28,10 @@ fun test() {
test(fun test() = 4)
}
-fun d = fun(a: Int,
- b: String) {
+fun d = fun(
+ a: Int,
+ b: String,
+) {
}
fun e = fun() {
diff --git a/idea/testData/formatter/LineBreakBeforeExtendsColon.after.kt b/idea/testData/formatter/LineBreakBeforeExtendsColon.after.kt
index e1724d793ba..f8a331b0057 100644
--- a/idea/testData/formatter/LineBreakBeforeExtendsColon.after.kt
+++ b/idea/testData/formatter/LineBreakBeforeExtendsColon.after.kt
@@ -1,4 +1,4 @@
open class GFMOutputBuilder(
- to: StringBuilder
+ to: StringBuilder,
) : MarkdownOutputBuilder(to) {
}
diff --git a/idea/testData/formatter/LineBreakBeforeExtendsColonWrap.after.kt b/idea/testData/formatter/LineBreakBeforeExtendsColonWrap.after.kt
index d119bee2087..aa3d159d354 100644
--- a/idea/testData/formatter/LineBreakBeforeExtendsColonWrap.after.kt
+++ b/idea/testData/formatter/LineBreakBeforeExtendsColonWrap.after.kt
@@ -1,5 +1,5 @@
open class GFMOutputBuilder(
- to: StringBuilder
+ to: StringBuilder,
) : MarkdownOutputBuilder(to) {
}
diff --git a/idea/testData/formatter/MethodLParenthOnNextLine.after.inv.kt b/idea/testData/formatter/MethodLParenthOnNextLine.after.inv.kt
index 443385d61e5..e3d1d7fd3ed 100644
--- a/idea/testData/formatter/MethodLParenthOnNextLine.after.inv.kt
+++ b/idea/testData/formatter/MethodLParenthOnNextLine.after.inv.kt
@@ -2,3 +2,4 @@ fun foo(a: String,
b: String)
// SET_TRUE: METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE
+// TRAILING_COMMA: false
\ No newline at end of file
diff --git a/idea/testData/formatter/MethodLParenthOnNextLine.after.kt b/idea/testData/formatter/MethodLParenthOnNextLine.after.kt
index 6d7d6473308..fead31e2336 100644
--- a/idea/testData/formatter/MethodLParenthOnNextLine.after.kt
+++ b/idea/testData/formatter/MethodLParenthOnNextLine.after.kt
@@ -3,3 +3,4 @@ fun foo(
b: String)
// SET_TRUE: METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE
+// TRAILING_COMMA: false
\ No newline at end of file
diff --git a/idea/testData/formatter/MethodLParenthOnNextLine.kt b/idea/testData/formatter/MethodLParenthOnNextLine.kt
index 443385d61e5..e3d1d7fd3ed 100644
--- a/idea/testData/formatter/MethodLParenthOnNextLine.kt
+++ b/idea/testData/formatter/MethodLParenthOnNextLine.kt
@@ -2,3 +2,4 @@ fun foo(a: String,
b: String)
// SET_TRUE: METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE
+// TRAILING_COMMA: false
\ No newline at end of file
diff --git a/idea/testData/formatter/MethodRParenthOnNextLine.after.inv.kt b/idea/testData/formatter/MethodRParenthOnNextLine.after.inv.kt
index 966a6dea8e5..ec482886d25 100644
--- a/idea/testData/formatter/MethodRParenthOnNextLine.after.inv.kt
+++ b/idea/testData/formatter/MethodRParenthOnNextLine.after.inv.kt
@@ -2,3 +2,4 @@ fun foo(a: String,
b: String)
// SET_TRUE: METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE
+// TRAILING_COMMA: false
\ No newline at end of file
diff --git a/idea/testData/formatter/MethodRParenthOnNextLine.after.kt b/idea/testData/formatter/MethodRParenthOnNextLine.after.kt
index b576dbc2ef6..40630933e33 100644
--- a/idea/testData/formatter/MethodRParenthOnNextLine.after.kt
+++ b/idea/testData/formatter/MethodRParenthOnNextLine.after.kt
@@ -3,3 +3,4 @@ fun foo(a: String,
)
// SET_TRUE: METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE
+// TRAILING_COMMA: false
\ No newline at end of file
diff --git a/idea/testData/formatter/MethodRParenthOnNextLine.kt b/idea/testData/formatter/MethodRParenthOnNextLine.kt
index 966a6dea8e5..ec482886d25 100644
--- a/idea/testData/formatter/MethodRParenthOnNextLine.kt
+++ b/idea/testData/formatter/MethodRParenthOnNextLine.kt
@@ -2,3 +2,4 @@ fun foo(a: String,
b: String)
// SET_TRUE: METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE
+// TRAILING_COMMA: false
\ No newline at end of file
diff --git a/idea/testData/formatter/NewLineForRBrace.after.kt b/idea/testData/formatter/NewLineForRBrace.after.kt
index 926fc8fb621..0f435b58ef3 100644
--- a/idea/testData/formatter/NewLineForRBrace.after.kt
+++ b/idea/testData/formatter/NewLineForRBrace.after.kt
@@ -45,4 +45,6 @@ fun commented1() {}
fun commented2() {}
// Comment
-fun commented3() {}
\ No newline at end of file
+fun commented3() {}
+
+// TRAILING_COMMA: false
\ No newline at end of file
diff --git a/idea/testData/formatter/NewLineForRBrace.kt b/idea/testData/formatter/NewLineForRBrace.kt
index 4e6d590565e..75962650359 100644
--- a/idea/testData/formatter/NewLineForRBrace.kt
+++ b/idea/testData/formatter/NewLineForRBrace.kt
@@ -39,4 +39,6 @@ fun commented1() {}
fun commented2() {}
// Comment
-fun commented3() {}
\ No newline at end of file
+fun commented3() {}
+
+// TRAILING_COMMA: false
\ No newline at end of file
diff --git a/idea/testData/formatter/ParameterAnnotationWrap.after.kt b/idea/testData/formatter/ParameterAnnotationWrap.after.kt
index 52c559b9c48..2c46fe6ff52 100644
--- a/idea/testData/formatter/ParameterAnnotationWrap.after.kt
+++ b/idea/testData/formatter/ParameterAnnotationWrap.after.kt
@@ -2,6 +2,7 @@ fun foo(@Deprecated("x")
x: Int,
@Deprecated("y")
@Deprecated("z")
- y: Int)
+ y: Int,
+)
// SET_INT: PARAMETER_ANNOTATION_WRAP = 2
diff --git a/idea/testData/formatter/ParameterDocComments.after.kt b/idea/testData/formatter/ParameterDocComments.after.kt
index 05b7fce125f..721503964ca 100644
--- a/idea/testData/formatter/ParameterDocComments.after.kt
+++ b/idea/testData/formatter/ParameterDocComments.after.kt
@@ -8,7 +8,8 @@ class A(
/**
* Doc
*/
- val p2: String)
+ val p2: String,
+)
class B(
/** Doc1 */
@@ -17,5 +18,5 @@ class B(
/**
* Doc2
*/
- val v2: Int
+ val v2: Int,
)
\ No newline at end of file
diff --git a/idea/testData/formatter/Parameters.after.inv.kt b/idea/testData/formatter/Parameters.after.inv.kt
index 276b8d36e73..fb03e1cfcc5 100644
--- a/idea/testData/formatter/Parameters.after.inv.kt
+++ b/idea/testData/formatter/Parameters.after.inv.kt
@@ -1,7 +1,7 @@
fun some(
a :Int,
b :String, c :Int,
- d :String, e :Int
+ d :String, e :Int,
) {
}
diff --git a/idea/testData/formatter/Parameters.after.kt b/idea/testData/formatter/Parameters.after.kt
index 7d801a1931e..4d5a3305e38 100644
--- a/idea/testData/formatter/Parameters.after.kt
+++ b/idea/testData/formatter/Parameters.after.kt
@@ -1,7 +1,7 @@
fun some(
a: Int,
b: String, c: Int,
- d: String, e: Int
+ d: String, e: Int,
) {
}
diff --git a/idea/testData/formatter/RightBracketOnNewLine.after.inv.kt b/idea/testData/formatter/RightBracketOnNewLine.after.inv.kt
index 19b2270ee30..11116308c4b 100644
--- a/idea/testData/formatter/RightBracketOnNewLine.after.inv.kt
+++ b/idea/testData/formatter/RightBracketOnNewLine.after.inv.kt
@@ -4,4 +4,5 @@ class Test {
}
}
-// SET_FALSE: ALIGN_MULTILINE_METHOD_BRACKETS
\ No newline at end of file
+// SET_FALSE: ALIGN_MULTILINE_METHOD_BRACKETS
+// TRAILING_COMMA: false
\ No newline at end of file
diff --git a/idea/testData/formatter/RightBracketOnNewLine.after.kt b/idea/testData/formatter/RightBracketOnNewLine.after.kt
index c66580708fb..39292fbda11 100644
--- a/idea/testData/formatter/RightBracketOnNewLine.after.kt
+++ b/idea/testData/formatter/RightBracketOnNewLine.after.kt
@@ -4,4 +4,5 @@ class Test {
}
}
-// SET_FALSE: ALIGN_MULTILINE_METHOD_BRACKETS
\ No newline at end of file
+// SET_FALSE: ALIGN_MULTILINE_METHOD_BRACKETS
+// TRAILING_COMMA: false
\ No newline at end of file
diff --git a/idea/testData/formatter/RightBracketOnNewLine.kt b/idea/testData/formatter/RightBracketOnNewLine.kt
index 6fb95fc392b..65cd54351a2 100644
--- a/idea/testData/formatter/RightBracketOnNewLine.kt
+++ b/idea/testData/formatter/RightBracketOnNewLine.kt
@@ -4,4 +4,5 @@ fun someLong(a : Int
}
}
-// SET_FALSE: ALIGN_MULTILINE_METHOD_BRACKETS
\ No newline at end of file
+// SET_FALSE: ALIGN_MULTILINE_METHOD_BRACKETS
+// TRAILING_COMMA: false
\ No newline at end of file
diff --git a/idea/testData/formatter/ValVarSpaces.after.kt b/idea/testData/formatter/ValVarSpaces.after.kt
index 682c2fb6b89..018f0816edc 100644
--- a/idea/testData/formatter/ValVarSpaces.after.kt
+++ b/idea/testData/formatter/ValVarSpaces.after.kt
@@ -2,4 +2,6 @@ class Foo(val x: Int,
var y: Int) {
val a = 1
var b = 2
-}
\ No newline at end of file
+}
+
+// TRAILING_COMMA: false
\ No newline at end of file
diff --git a/idea/testData/formatter/ValVarSpaces.kt b/idea/testData/formatter/ValVarSpaces.kt
index e94c2dbdfa7..94941f36efe 100644
--- a/idea/testData/formatter/ValVarSpaces.kt
+++ b/idea/testData/formatter/ValVarSpaces.kt
@@ -2,4 +2,6 @@ class Foo(val x: Int,
var y: Int) {
val a = 1
var b = 2
-}
\ No newline at end of file
+}
+
+// TRAILING_COMMA: false
\ No newline at end of file
diff --git a/idea/testData/formatter/WhereClause.after.kt b/idea/testData/formatter/WhereClause.after.kt
index 61fafbbbbf0..58606cdfe68 100644
--- a/idea/testData/formatter/WhereClause.after.kt
+++ b/idea/testData/formatter/WhereClause.after.kt
@@ -1,6 +1,6 @@
abstract class RustNavigationContributorBase protected constructor(
private val indexKey: StubIndexKey,
- private val clazz: Class
+ private val clazz: Class,
) : ChooseByNameContributor, GotoClassContributor
where T : NavigationItem,
T : RustNamedElement {
diff --git a/idea/testData/formatter/parameterList/DefaultParameterValues.after.inv.kt b/idea/testData/formatter/parameterList/DefaultParameterValues.after.inv.kt
index f91e65f4fb9..bc0813527c7 100644
--- a/idea/testData/formatter/parameterList/DefaultParameterValues.after.inv.kt
+++ b/idea/testData/formatter/parameterList/DefaultParameterValues.after.inv.kt
@@ -1,12 +1,12 @@
fun foo(
x: Int =
- 42
+ 42,
) {
}
class C(
val x: Int =
- 42
+ 42,
)
// SET_TRUE: CONTINUATION_INDENT_FOR_EXPRESSION_BODIES
diff --git a/idea/testData/formatter/parameterList/DefaultParameterValues.after.kt b/idea/testData/formatter/parameterList/DefaultParameterValues.after.kt
index 0c5e97ef42d..d1b0a9acf49 100644
--- a/idea/testData/formatter/parameterList/DefaultParameterValues.after.kt
+++ b/idea/testData/formatter/parameterList/DefaultParameterValues.after.kt
@@ -1,12 +1,12 @@
fun foo(
x: Int =
- 42
+ 42,
) {
}
class C(
val x: Int =
- 42
+ 42,
)
// SET_TRUE: CONTINUATION_INDENT_FOR_EXPRESSION_BODIES
diff --git a/idea/testData/formatter/parameterList/ParameterListChopAsNeeded.after.kt b/idea/testData/formatter/parameterList/ParameterListChopAsNeeded.after.kt
index cae295a237e..4bed1eb61f2 100644
--- a/idea/testData/formatter/parameterList/ParameterListChopAsNeeded.after.kt
+++ b/idea/testData/formatter/parameterList/ParameterListChopAsNeeded.after.kt
@@ -15,7 +15,8 @@ fun test(foo: Int, bar: Int)
fun testtesttesttest(foofoo: Int,
barbar: Int,
foobar: Int,
- barfoo: Int)
+ barfoo: Int,
+)
fun test() {
for (foo: Int in bar) {
@@ -41,20 +42,24 @@ class SN
class A(longLongLongLongNameCLass1: LongLongLongLongNameCLass,
longLongLongLongNameCLass2: LongLongLongLongNameCLass,
- longLongLongLongNameCLass3: LongLongLongLongNameCLass) {
+ longLongLongLongNameCLass3: LongLongLongLongNameCLass,
+) {
constructor(
longLongLongLongNameCLass1: LongLongLongLongNameCLass,
longLongLongLongNameCLass2: LongLongLongLongNameCLass,
- longLongLongLongNameCLass3: LongLongLongLongNameCLass) {
+ longLongLongLongNameCLass3: LongLongLongLongNameCLass,
+ ) {
}
}
class B(a: LongLongLongLongNameCLass,
b: LongLongLongLongNameCLass,
- c: LongLongLongLongNameCLass) {
+ c: LongLongLongLongNameCLass,
+) {
constructor(a: LongLongLongLongNameCLass,
b: LongLongLongLongNameCLass,
- c: LongLongLongLongNameCLass) {
+ c: LongLongLongLongNameCLass,
+ ) {
}
}
@@ -66,7 +71,8 @@ class C(sn1: ShorName,
sn6: ShorName,
sn6: ShorName,
sn8: ShorName,
- sn9: ShorName) {
+ sn9: ShorName,
+) {
constructor(sn1: ShorName,
sn2: ShorName,
sn3: ShorName,
@@ -75,7 +81,8 @@ class C(sn1: ShorName,
sn6: ShorName,
sn6: ShorName,
sn8: ShorName,
- sn9: ShorName) {
+ sn9: ShorName,
+ ) {
}
}
@@ -92,7 +99,8 @@ class D(sn1: SN,
sn11: SN,
sn12: SN,
sn13: SN,
- sn14: SN) {
+ sn14: SN,
+) {
constructor(sn1: SN,
sn2: SN,
sn3: SN,
@@ -106,13 +114,15 @@ class D(sn1: SN,
sn11: SN,
sn12: SN,
sn13: SN,
- sn14: SN) {
+ sn14: SN,
+ ) {
}
}
class E(longLongLongLongNameCLass1: LongLongLongLongNameCLass) {
constructor(
- longLongLongLongNameCLass1: LongLongLongLongNameCLass) {
+ longLongLongLongNameCLass1: LongLongLongLongNameCLass,
+ ) {
}
}
diff --git a/idea/testData/formatter/parameterList/ParameterListWrapAlways.after.kt b/idea/testData/formatter/parameterList/ParameterListWrapAlways.after.kt
index 270799b10df..a132fcbb979 100644
--- a/idea/testData/formatter/parameterList/ParameterListWrapAlways.after.kt
+++ b/idea/testData/formatter/parameterList/ParameterListWrapAlways.after.kt
@@ -11,22 +11,26 @@ fun testtest(foofoo: Int)
fun testtesttesttest(foofoo: Int)
fun test(foo: Int,
- bar: Int)
+ bar: Int,
+)
fun testtesttesttest(foofoo: Int,
barbar: Int,
foobar: Int,
- barfoo: Int)
+ barfoo: Int,
+)
fun testtesttesttest(foofoo: Int,
@Some barbar: Int,
foobar: Int,
- barfoo: Int)
+ barfoo: Int,
+)
fun testtesttesttest(@Some foofoo: Int,
@Some barbar: Int,
@Some foobar: Int,
- barfoo: Int)
+ barfoo: Int,
+)
fun test() {
for (foo: Int in bar) {
@@ -52,19 +56,23 @@ class SN
class A(longLongLongLongNameCLass1: LongLongLongLongNameCLass,
longLongLongLongNameCLass2: LongLongLongLongNameCLass,
- longLongLongLongNameCLass3: LongLongLongLongNameCLass) {
+ longLongLongLongNameCLass3: LongLongLongLongNameCLass,
+) {
constructor(longLongLongLongNameCLass1: LongLongLongLongNameCLass,
longLongLongLongNameCLass2: LongLongLongLongNameCLass,
- longLongLongLongNameCLass3: LongLongLongLongNameCLass) {
+ longLongLongLongNameCLass3: LongLongLongLongNameCLass,
+ ) {
}
}
class B(a: LongLongLongLongNameCLass,
b: LongLongLongLongNameCLass,
- c: LongLongLongLongNameCLass) {
+ c: LongLongLongLongNameCLass,
+) {
constructor(a: LongLongLongLongNameCLass,
b: LongLongLongLongNameCLass,
- c: LongLongLongLongNameCLass) {
+ c: LongLongLongLongNameCLass,
+ ) {
}
}
@@ -76,7 +84,8 @@ class C(sn1: ShorName,
sn6: ShorName,
sn6: ShorName,
sn8: ShorName,
- sn9: ShorName) {
+ sn9: ShorName,
+) {
constructor(sn1: ShorName,
sn2: ShorName,
sn3: ShorName,
@@ -85,7 +94,8 @@ class C(sn1: ShorName,
sn6: ShorName,
sn6: ShorName,
sn8: ShorName,
- sn9: ShorName) {
+ sn9: ShorName,
+ ) {
}
}
@@ -102,7 +112,8 @@ class D(sn1: SN,
sn11: SN,
sn12: SN,
sn13: SN,
- sn14: SN) {
+ sn14: SN,
+) {
constructor(sn1: SN,
sn2: SN,
sn3: SN,
@@ -116,7 +127,8 @@ class D(sn1: SN,
sn11: SN,
sn12: SN,
sn13: SN,
- sn14: SN) {
+ sn14: SN,
+ ) {
}
}
@@ -136,7 +148,8 @@ class G(sn1: ShorName) {
}
class H(sn1: SN,
- sn2: SN) {
+ sn2: SN,
+) {
constructor(sn1: SN) {
}
}
@@ -154,7 +167,8 @@ class I(sn1: SN,
sn11: SN,
sn12: SN,
sn13: SN,
- sn14: SN) {
+ sn14: SN,
+) {
constructor(sn1: SN,
sn2: SN,
sn3: SN,
@@ -168,6 +182,7 @@ class I(sn1: SN,
sn11: SN,
sn12: SN,
sn13: SN,
- sn14: SN) {
+ sn14: SN,
+ ) {
}
}
diff --git a/idea/testData/formatter/parameterList/ParameterListWrapAsNeeded.after.kt b/idea/testData/formatter/parameterList/ParameterListWrapAsNeeded.after.kt
index c119f6f61cd..8124c26daa6 100644
--- a/idea/testData/formatter/parameterList/ParameterListWrapAsNeeded.after.kt
+++ b/idea/testData/formatter/parameterList/ParameterListWrapAsNeeded.after.kt
@@ -9,7 +9,8 @@ fun testtesttesttesttesttesttesttesttest()
fun testtest(foofoo: Int)
fun testtesttesttest(
- foofoo: Int)
+ foofoo: Int,
+)
fun test(foo: Int, bar: Int)
@@ -17,7 +18,8 @@ fun testtesttesttest(
foofoo: Int,
barbar: Int,
foobar: Int,
- barfoo: Int)
+ barfoo: Int,
+)
fun test() {
for (foo: Int in bar) {
@@ -43,21 +45,25 @@ class SN
class A(longLongLongLongNameCLass1: LongLongLongLongNameCLass,
longLongLongLongNameCLass2: LongLongLongLongNameCLass,
- longLongLongLongNameCLass3: LongLongLongLongNameCLass) {
+ longLongLongLongNameCLass3: LongLongLongLongNameCLass,
+) {
constructor(
longLongLongLongNameCLass1: LongLongLongLongNameCLass,
longLongLongLongNameCLass2: LongLongLongLongNameCLass,
- longLongLongLongNameCLass3: LongLongLongLongNameCLass) {
+ longLongLongLongNameCLass3: LongLongLongLongNameCLass,
+ ) {
}
}
class B(a: LongLongLongLongNameCLass,
b: LongLongLongLongNameCLass,
- c: LongLongLongLongNameCLass) {
+ c: LongLongLongLongNameCLass,
+) {
constructor(
a: LongLongLongLongNameCLass,
b: LongLongLongLongNameCLass,
- c: LongLongLongLongNameCLass) {
+ c: LongLongLongLongNameCLass,
+ ) {
}
}
@@ -69,7 +75,8 @@ class C(sn1: ShorName,
sn6: ShorName,
sn6: ShorName,
sn8: ShorName,
- sn9: ShorName) {
+ sn9: ShorName,
+) {
constructor(sn1: ShorName,
sn2: ShorName,
sn3: ShorName,
@@ -78,7 +85,8 @@ class C(sn1: ShorName,
sn6: ShorName,
sn6: ShorName,
sn8: ShorName,
- sn9: ShorName) {
+ sn9: ShorName,
+ ) {
}
}
@@ -88,7 +96,8 @@ class D(sn1: SN, sn2: SN,
sn6: SN, sn8: SN,
sn9: SN, sn10: SN,
sn11: SN, sn12: SN,
- sn13: SN, sn14: SN) {
+ sn13: SN, sn14: SN,
+) {
constructor(sn1: SN,
sn2: SN,
sn3: SN,
@@ -102,25 +111,29 @@ class D(sn1: SN, sn2: SN,
sn11: SN,
sn12: SN,
sn13: SN,
- sn14: SN) {
+ sn14: SN,
+ ) {
}
}
class E(longLongLongLongNameCLass1: LongLongLongLongNameCLass) {
constructor(
- longLongLongLongNameCLass1: LongLongLongLongNameCLass) {
+ longLongLongLongNameCLass1: LongLongLongLongNameCLass,
+ ) {
}
}
class F(a: LongLongLongLongNameCLass) {
constructor(
- a: LongLongLongLongNameCLass) {
+ a: LongLongLongLongNameCLass,
+ ) {
}
}
class G(sn1: ShorName) {
constructor(
- sn1: ShorName) {
+ sn1: ShorName,
+ ) {
}
}
diff --git a/idea/testData/formatter/trailingComma/valueParameters/Function.after.inv.kt b/idea/testData/formatter/trailingComma/valueParameters/Function.after.inv.kt
new file mode 100644
index 00000000000..a4f67211ac8
--- /dev/null
+++ b/idea/testData/formatter/trailingComma/valueParameters/Function.after.inv.kt
@@ -0,0 +1,85 @@
+fun a1(
+ x: String,
+ y: String,
+) = Unit
+
+fun b1(
+ x: String,
+ y: String
+) = Unit
+
+fun c1(
+ x: String,
+ y: String,
+) = Unit
+
+fun d1(
+ x: String,
+ y: String,
+) = Unit
+
+fun a2(
+ x: String,
+ y: String,
+ z: String,
+) = Unit
+
+fun b2(
+ x: String,
+ y: String,
+ z: String
+) = Unit
+
+fun c2(
+ x: String,
+ y: String,
+ z: String,
+) = Unit
+
+fun d2(
+ x: String,
+ y: String,
+ z: String,
+) = Unit
+
+fun a3(
+ x: String,
+) = Unit
+
+fun b3(
+ x: String
+) = Unit
+
+fun c3(
+ x: String,
+) = Unit
+
+fun d3(
+ x: String,
+) = Unit
+
+fun a4(
+ x: String,
+ y: String,
+ z: String,
+) = Unit
+
+fun b4(
+ x: String,
+ y: String,
+ z: String
+) = Unit
+
+fun c4(
+ x: String,
+ y: String,
+ z: String,
+) = Unit
+
+fun d4(
+ x: String,
+ y: String,
+ z: String,
+) = Unit
+
+// SET_TRUE: ALLOW_TRAILING_COMMA
\ No newline at end of file
diff --git a/idea/testData/formatter/trailingComma/valueParameters/Function.after.kt b/idea/testData/formatter/trailingComma/valueParameters/Function.after.kt
new file mode 100644
index 00000000000..f1e58ea65cd
--- /dev/null
+++ b/idea/testData/formatter/trailingComma/valueParameters/Function.after.kt
@@ -0,0 +1,85 @@
+fun a1(
+ x: String,
+ y: String,
+) = Unit
+
+fun b1(
+ x: String,
+ y: String,
+) = Unit
+
+fun c1(
+ x: String,
+ y: String,
+) = Unit
+
+fun d1(
+ x: String,
+ y: String,
+) = Unit
+
+fun a2(
+ x: String,
+ y: String,
+ z: String,
+) = Unit
+
+fun b2(
+ x: String,
+ y: String,
+ z: String,
+) = Unit
+
+fun c2(
+ x: String,
+ y: String,
+ z: String,
+) = Unit
+
+fun d2(
+ x: String,
+ y: String,
+ z: String,
+) = Unit
+
+fun a3(
+ x: String,
+) = Unit
+
+fun b3(
+ x: String,
+) = Unit
+
+fun c3(
+ x: String,
+) = Unit
+
+fun d3(
+ x: String,
+) = Unit
+
+fun a4(
+ x: String,
+ y: String,
+ z: String,
+) = Unit
+
+fun b4(
+ x: String,
+ y: String,
+ z: String,
+) = Unit
+
+fun c4(
+ x: String,
+ y: String,
+ z: String,
+) = Unit
+
+fun d4(
+ x: String,
+ y: String,
+ z: String,
+) = Unit
+
+// SET_TRUE: ALLOW_TRAILING_COMMA
\ No newline at end of file
diff --git a/idea/testData/formatter/trailingComma/valueParameters/Function.kt b/idea/testData/formatter/trailingComma/valueParameters/Function.kt
new file mode 100644
index 00000000000..839cffeda09
--- /dev/null
+++ b/idea/testData/formatter/trailingComma/valueParameters/Function.kt
@@ -0,0 +1,81 @@
+fun a1(
+ x: String,
+ y: String,
+) = Unit
+
+fun b1(
+ x: String,
+ y: String
+) = Unit
+
+fun c1(
+ x: String,
+ y: String,) = Unit
+
+fun d1(
+ x: String,
+ y: String
+ ,) = Unit
+
+fun a2(
+ x: String,
+ y: String,
+ z: String,
+) = Unit
+
+fun b2(
+ x: String,
+ y: String,
+ z: String
+) = Unit
+
+fun c2(
+ x: String,
+ y: String,
+ z: String,) = Unit
+
+fun d2(
+ x: String,
+ y: String,
+ z: String
+ ,) = Unit
+
+fun a3(
+ x: String,
+) = Unit
+
+fun b3(
+ x: String
+) = Unit
+
+fun c3(
+ x: String,) = Unit
+
+fun d3(
+ x: String
+ ,) = Unit
+
+fun a4(
+ x: String
+ ,
+ y: String,
+ z: String ,
+) = Unit
+
+fun b4(
+ x: String,
+ y: String,
+ z: String
+) = Unit
+
+fun c4(x: String,
+ y: String,
+ z: String ,) = Unit
+
+fun d4(
+ x: String,
+ y: String,
+ z: String
+, ) = Unit
+
+// SET_TRUE: ALLOW_TRAILING_COMMA
\ No newline at end of file
diff --git a/idea/testData/formatter/trailingComma/valueParameters/OptionalTypes.after.inv.kt b/idea/testData/formatter/trailingComma/valueParameters/OptionalTypes.after.inv.kt
new file mode 100644
index 00000000000..f3f577e0628
--- /dev/null
+++ b/idea/testData/formatter/trailingComma/valueParameters/OptionalTypes.after.inv.kt
@@ -0,0 +1,75 @@
+val foo1: (Int, Int) -> Int = fun(
+ x,
+ y,
+): Int = 42
+
+val foo2: (Int, Int) -> Int = fun(
+ x,
+ y
+): Int {
+ return x + y
+}
+
+val foo3: (Int, Int) -> Int = fun(
+ x, y,
+): Int {
+ return x + y
+}
+
+val foo4: (Int) -> Int = fun(
+ x,
+): Int = 42
+
+val foo5: (Int) -> Int = fun(
+ x
+): Int = 42
+
+val foo6: (Int) -> Int = fun(
+ x,
+): Int = 42
+
+val foo7: (Int) -> Int = fun(x): Int = 42
+
+val foo8: (Int, Int, Int) -> Int = fun(
+ x, y: Int, z,
+): Int {
+ return x + y
+}
+
+val foo9: (Int, Int, Int) -> Int = fun(
+ x,
+ y: Int,
+ z,
+): Int = 42
+
+val foo10: (Int, Int, Int) -> Int = fun(
+ x,
+ y: Int,
+ z: Int
+): Int = 43
+
+val foo10 = fun(
+ x: Int,
+ y: Int,
+ z: Int
+): Int = 43
+
+val foo11 = fun(
+ x: Int,
+ y: Int,
+ z: Int,
+): Int = 43
+
+val foo12 = fun(
+ x: Int, y: Int, z: Int,
+): Int = 43
+
+val foo13 = fun(
+ x: Int, y: Int, z: Int,
+): Int = 43
+
+val foo14 = fun(
+ x: Int, y: Int, z: Int,
+): Int = 43
+
+// SET_TRUE: ALLOW_TRAILING_COMMA
\ No newline at end of file
diff --git a/idea/testData/formatter/trailingComma/valueParameters/OptionalTypes.after.kt b/idea/testData/formatter/trailingComma/valueParameters/OptionalTypes.after.kt
new file mode 100644
index 00000000000..e581494c562
--- /dev/null
+++ b/idea/testData/formatter/trailingComma/valueParameters/OptionalTypes.after.kt
@@ -0,0 +1,75 @@
+val foo1: (Int, Int) -> Int = fun(
+ x,
+ y,
+): Int = 42
+
+val foo2: (Int, Int) -> Int = fun(
+ x,
+ y,
+): Int {
+ return x + y
+}
+
+val foo3: (Int, Int) -> Int = fun(
+ x, y,
+): Int {
+ return x + y
+}
+
+val foo4: (Int) -> Int = fun(
+ x,
+): Int = 42
+
+val foo5: (Int) -> Int = fun(
+ x,
+): Int = 42
+
+val foo6: (Int) -> Int = fun(
+ x,
+): Int = 42
+
+val foo7: (Int) -> Int = fun(x): Int = 42
+
+val foo8: (Int, Int, Int) -> Int = fun(
+ x, y: Int, z,
+): Int {
+ return x + y
+}
+
+val foo9: (Int, Int, Int) -> Int = fun(
+ x,
+ y: Int,
+ z,
+): Int = 42
+
+val foo10: (Int, Int, Int) -> Int = fun(
+ x,
+ y: Int,
+ z: Int,
+): Int = 43
+
+val foo10 = fun(
+ x: Int,
+ y: Int,
+ z: Int,
+): Int = 43
+
+val foo11 = fun(
+ x: Int,
+ y: Int,
+ z: Int,
+): Int = 43
+
+val foo12 = fun(
+ x: Int, y: Int, z: Int,
+): Int = 43
+
+val foo13 = fun(
+ x: Int, y: Int, z: Int,
+): Int = 43
+
+val foo14 = fun(
+ x: Int, y: Int, z: Int,
+): Int = 43
+
+// SET_TRUE: ALLOW_TRAILING_COMMA
\ No newline at end of file
diff --git a/idea/testData/formatter/trailingComma/valueParameters/OptionalTypes.kt b/idea/testData/formatter/trailingComma/valueParameters/OptionalTypes.kt
new file mode 100644
index 00000000000..3169be915e9
--- /dev/null
+++ b/idea/testData/formatter/trailingComma/valueParameters/OptionalTypes.kt
@@ -0,0 +1,69 @@
+val foo1: (Int, Int) -> Int = fun(
+ x,
+ y,
+): Int = 42
+
+val foo2: (Int, Int) -> Int = fun(
+ x,
+ y
+): Int {
+ return x + y
+}
+
+val foo3: (Int, Int) -> Int = fun(
+ x, y,
+): Int {
+ return x + y
+}
+
+val foo4: (Int) -> Int = fun(
+ x,
+): Int = 42
+
+val foo5: (Int) -> Int = fun(
+ x
+): Int = 42
+
+val foo6: (Int) -> Int = fun(x,): Int = 42
+
+val foo7: (Int) -> Int = fun(x): Int = 42
+
+val foo8: (Int, Int, Int) -> Int = fun (x, y: Int, z,): Int {
+ return x + y
+ }
+
+val foo9: (Int, Int, Int) -> Int = fun (
+ x,
+ y: Int,
+ z,
+): Int = 42
+
+val foo10: (Int, Int, Int) -> Int = fun (
+ x,
+ y: Int,
+ z: Int
+): Int = 43
+
+val foo10 = fun (
+ x: Int,
+ y: Int,
+ z: Int
+): Int = 43
+
+val foo11 = fun (
+ x: Int,
+ y: Int,
+ z: Int,
+): Int = 43
+
+val foo12 = fun (
+ x: Int, y: Int, z: Int,
+): Int = 43
+
+val foo13 = fun (x: Int, y: Int, z: Int,
+): Int = 43
+
+val foo14 = fun (x: Int, y: Int, z: Int
+ ,): Int = 43
+
+// SET_TRUE: ALLOW_TRAILING_COMMA
\ No newline at end of file
diff --git a/idea/testData/formatter/trailingComma/valueParameters/PrimaryConstructor.after.inv.kt b/idea/testData/formatter/trailingComma/valueParameters/PrimaryConstructor.after.inv.kt
new file mode 100644
index 00000000000..d0c85606d0b
--- /dev/null
+++ b/idea/testData/formatter/trailingComma/valueParameters/PrimaryConstructor.after.inv.kt
@@ -0,0 +1,94 @@
+class A1(
+ val x: String,
+ y: String,
+)
+
+class B1(
+ val x: String,
+ val y: String
+)
+
+class C1(
+ val x: String,
+ val y: String,
+)
+
+class D1(
+ val x: String,
+ val y: String,
+)
+
+class A2(
+ val x: String,
+ val y: String,
+ val z: String,
+)
+
+class B2(
+ val x: String,
+ val y: String,
+ val z: String
+)
+
+class C2(
+ val x: String,
+ val y: String,
+ val z: String,
+)
+
+class D2(
+ val x: String,
+ val y: String,
+ val z: String,
+)
+
+class A3(
+ val x: String,
+)
+
+class B3(
+ val x: String
+)
+
+class C3(
+ val x: String,
+)
+
+class D3(
+ val x: String,
+)
+
+class A4(
+ val x: String,
+ val y: String,
+ val z: String,
+)
+
+class B4(
+ val x: String,
+ val y: String,
+ val z: String
+)
+
+class C4(
+ val x: String,
+ val y: String,
+ val z: String,
+)
+
+class D4(
+ val x: String,
+ val y: String,
+ val z: String,
+)
+
+class E1(
+ val x: String, val y: String,
+ val z: String,
+)
+
+class E2(
+ val x: String, val y: String, val z: String
+)
+
+// SET_TRUE: ALLOW_TRAILING_COMMA
\ No newline at end of file
diff --git a/idea/testData/formatter/trailingComma/valueParameters/PrimaryConstructor.after.kt b/idea/testData/formatter/trailingComma/valueParameters/PrimaryConstructor.after.kt
new file mode 100644
index 00000000000..9332404b41b
--- /dev/null
+++ b/idea/testData/formatter/trailingComma/valueParameters/PrimaryConstructor.after.kt
@@ -0,0 +1,94 @@
+class A1(
+ val x: String,
+ y: String,
+)
+
+class B1(
+ val x: String,
+ val y: String,
+)
+
+class C1(
+ val x: String,
+ val y: String,
+)
+
+class D1(
+ val x: String,
+ val y: String,
+)
+
+class A2(
+ val x: String,
+ val y: String,
+ val z: String,
+)
+
+class B2(
+ val x: String,
+ val y: String,
+ val z: String,
+)
+
+class C2(
+ val x: String,
+ val y: String,
+ val z: String,
+)
+
+class D2(
+ val x: String,
+ val y: String,
+ val z: String,
+)
+
+class A3(
+ val x: String,
+)
+
+class B3(
+ val x: String,
+)
+
+class C3(
+ val x: String,
+)
+
+class D3(
+ val x: String,
+)
+
+class A4(
+ val x: String,
+ val y: String,
+ val z: String,
+)
+
+class B4(
+ val x: String,
+ val y: String,
+ val z: String,
+)
+
+class C4(
+ val x: String,
+ val y: String,
+ val z: String,
+)
+
+class D4(
+ val x: String,
+ val y: String,
+ val z: String,
+)
+
+class E1(
+ val x: String, val y: String,
+ val z: String,
+)
+
+class E2(
+ val x: String, val y: String, val z: String,
+)
+
+// SET_TRUE: ALLOW_TRAILING_COMMA
\ No newline at end of file
diff --git a/idea/testData/formatter/trailingComma/valueParameters/PrimaryConstructor.kt b/idea/testData/formatter/trailingComma/valueParameters/PrimaryConstructor.kt
new file mode 100644
index 00000000000..0b48f37a610
--- /dev/null
+++ b/idea/testData/formatter/trailingComma/valueParameters/PrimaryConstructor.kt
@@ -0,0 +1,90 @@
+class A1(
+ val x: String,
+ y: String,
+)
+
+class B1(
+ val x: String,
+ val y: String
+)
+
+class C1(
+ val x: String,
+ val y: String,)
+
+class D1(
+ val x: String,
+ val y: String
+ ,)
+
+class A2(
+ val x: String,
+ val y: String,
+ val z: String,
+)
+
+class B2(
+ val x: String,
+ val y: String,
+ val z: String
+)
+
+class C2(
+ val x: String,
+ val y: String,
+ val z: String,)
+
+class D2(
+ val x: String,
+ val y: String,
+ val z: String
+ ,)
+
+class A3(
+ val x: String,
+)
+
+class B3(
+ val x: String
+)
+
+class C3(
+ val x: String,)
+
+class D3(
+ val x: String
+ ,)
+
+class A4(
+ val x: String ,
+ val y: String,
+ val z: String ,
+)
+
+class B4(
+ val x: String,
+ val y: String,
+ val z: String
+)
+
+class C4(
+ val x: String,
+ val y: String,
+ val z: String ,)
+
+class D4(
+ val x: String,
+ val y: String,
+ val z: String
+, )
+
+class E1(
+ val x: String, val y: String,
+ val z: String
+, )
+
+class E2(
+ val x: String, val y: String, val z: String
+)
+
+// SET_TRUE: ALLOW_TRAILING_COMMA
\ No newline at end of file
diff --git a/idea/testData/formatter/trailingComma/valueParameters/SecondConstructor.after.inv.kt b/idea/testData/formatter/trailingComma/valueParameters/SecondConstructor.after.inv.kt
new file mode 100644
index 00000000000..0f4d61ea74a
--- /dev/null
+++ b/idea/testData/formatter/trailingComma/valueParameters/SecondConstructor.after.inv.kt
@@ -0,0 +1,184 @@
+class A1 {
+ val x: String
+ val y: String
+
+ constructor(
+ x: String,
+ y: String,
+ ) {
+ this.x = x
+ this.y = y
+ }
+}
+
+class B1 {
+ val x: String
+ val y: String
+
+ constructor(
+ x: String,
+ y: String
+ ) {
+ this.x = x
+ this.y = y
+ }
+}
+
+class C1 {
+ val x: String
+ val y: String
+
+ constructor(
+ x: String,
+ y: String,
+ ) {
+ this.x = x
+ this.y = y
+ }
+}
+
+class D1 {
+ val x: String
+ val y: String
+
+ constructor(
+ x: String,
+ y: String,
+ ) {
+ this.x = x
+ this.y = y
+ }
+}
+
+class A2 {
+ val x: String
+ val y: String
+ val z: String
+
+ constructor(
+ x: String,
+ y: String,
+ z: String,
+ ) {
+ this.x = x
+ this.y = y
+ this.z = z
+ }
+}
+
+class B2 {
+ val x: String
+ val y: String
+ val z: String
+
+ constructor(
+ x: String,
+ y: String,
+ z: String
+ ) {
+ this.x = x
+ this.y = y
+ this.z = z
+ }
+}
+
+class C2 {
+ val x: String
+ val y: String
+ val z: String
+
+ constructor(
+ x: String,
+ y: String,
+ z: String,
+ ) {
+ this.x = x
+ this.y = y
+ this.z = z
+ }
+}
+
+class D2 {
+ val x: String
+ val y: String
+ val z: String
+
+ constructor(
+ x: String,
+ y: String,
+ z: String,
+ ) {
+ this.x = x
+ this.y = y
+ this.z = z
+ }
+}
+
+class A3 {
+ val x: String
+
+ constructor(
+ x: String,
+ ) {
+ this.x = x
+ }
+}
+
+class B3 {
+ val x: String
+
+ constructor(x: String) {
+ this.x = x
+ }
+}
+
+class C3 {
+ val x: String
+
+ constructor(
+ x: String,
+ ) {
+ this.x = x
+ }
+}
+
+class D3 {
+ val x: String
+
+ constructor(
+ x: String,
+ ) {
+ this.x = x
+ }
+}
+
+class E1 {
+ val x: String
+ val y: String
+ val z: String
+
+ constructor(
+ x: String,
+ y: String, z: String,
+ ) {
+ this.x = x
+ this.y = y
+ this.z = z
+ }
+}
+
+class E2 {
+ val x: String
+ val y: String
+ val z: String
+
+ constructor(
+ x: String,
+ y: String, z: String) {
+ this.x = x
+ this.y = y
+ this.z = z
+ }
+}
+
+// SET_TRUE: ALLOW_TRAILING_COMMA
\ No newline at end of file
diff --git a/idea/testData/formatter/trailingComma/valueParameters/SecondConstructor.after.kt b/idea/testData/formatter/trailingComma/valueParameters/SecondConstructor.after.kt
new file mode 100644
index 00000000000..869494dcbcc
--- /dev/null
+++ b/idea/testData/formatter/trailingComma/valueParameters/SecondConstructor.after.kt
@@ -0,0 +1,185 @@
+class A1 {
+ val x: String
+ val y: String
+
+ constructor(
+ x: String,
+ y: String,
+ ) {
+ this.x = x
+ this.y = y
+ }
+}
+
+class B1 {
+ val x: String
+ val y: String
+
+ constructor(
+ x: String,
+ y: String,
+ ) {
+ this.x = x
+ this.y = y
+ }
+}
+
+class C1 {
+ val x: String
+ val y: String
+
+ constructor(
+ x: String,
+ y: String,
+ ) {
+ this.x = x
+ this.y = y
+ }
+}
+
+class D1 {
+ val x: String
+ val y: String
+
+ constructor(
+ x: String,
+ y: String,
+ ) {
+ this.x = x
+ this.y = y
+ }
+}
+
+class A2 {
+ val x: String
+ val y: String
+ val z: String
+
+ constructor(
+ x: String,
+ y: String,
+ z: String,
+ ) {
+ this.x = x
+ this.y = y
+ this.z = z
+ }
+}
+
+class B2 {
+ val x: String
+ val y: String
+ val z: String
+
+ constructor(
+ x: String,
+ y: String,
+ z: String,
+ ) {
+ this.x = x
+ this.y = y
+ this.z = z
+ }
+}
+
+class C2 {
+ val x: String
+ val y: String
+ val z: String
+
+ constructor(
+ x: String,
+ y: String,
+ z: String,
+ ) {
+ this.x = x
+ this.y = y
+ this.z = z
+ }
+}
+
+class D2 {
+ val x: String
+ val y: String
+ val z: String
+
+ constructor(
+ x: String,
+ y: String,
+ z: String,
+ ) {
+ this.x = x
+ this.y = y
+ this.z = z
+ }
+}
+
+class A3 {
+ val x: String
+
+ constructor(
+ x: String,
+ ) {
+ this.x = x
+ }
+}
+
+class B3 {
+ val x: String
+
+ constructor(x: String) {
+ this.x = x
+ }
+}
+
+class C3 {
+ val x: String
+
+ constructor(
+ x: String,
+ ) {
+ this.x = x
+ }
+}
+
+class D3 {
+ val x: String
+
+ constructor(
+ x: String,
+ ) {
+ this.x = x
+ }
+}
+
+class E1 {
+ val x: String
+ val y: String
+ val z: String
+
+ constructor(
+ x: String,
+ y: String, z: String,
+ ) {
+ this.x = x
+ this.y = y
+ this.z = z
+ }
+}
+
+class E2 {
+ val x: String
+ val y: String
+ val z: String
+
+ constructor(
+ x: String,
+ y: String, z: String,
+ ) {
+ this.x = x
+ this.y = y
+ this.z = z
+ }
+}
+
+// SET_TRUE: ALLOW_TRAILING_COMMA
\ No newline at end of file
diff --git a/idea/testData/formatter/trailingComma/valueParameters/SecondConstructor.kt b/idea/testData/formatter/trailingComma/valueParameters/SecondConstructor.kt
new file mode 100644
index 00000000000..08502f225cb
--- /dev/null
+++ b/idea/testData/formatter/trailingComma/valueParameters/SecondConstructor.kt
@@ -0,0 +1,178 @@
+class A1 {
+ val x: String
+ val y: String
+
+ constructor(
+ x: String,
+ y: String,
+ ) {
+ this.x = x
+ this.y = y
+ }
+}
+
+class B1 {
+ val x: String
+ val y: String
+
+ constructor(
+ x: String,
+ y: String
+ ) {
+ this.x = x
+ this.y = y
+ }
+}
+
+class C1 {
+ val x: String
+ val y: String
+
+ constructor(
+ x: String,
+ y: String,) {
+ this.x = x
+ this.y = y
+ }
+}
+
+class D1 {
+ val x: String
+ val y: String
+
+ constructor(
+ x: String,
+ y: String
+ ,) {
+ this.x = x
+ this.y = y
+ }
+}
+
+class A2 {
+ val x: String
+ val y: String
+ val z: String
+
+ constructor(
+ x: String,
+ y: String,
+ z: String,
+ ) {
+ this.x = x
+ this.y = y
+ this.z = z
+ }
+}
+
+class B2 {
+ val x: String
+ val y: String
+ val z: String
+
+ constructor(
+ x: String,
+ y: String,
+ z: String
+ ) {
+ this.x = x
+ this.y = y
+ this.z = z
+ }
+}
+
+class C2 {
+ val x: String
+ val y: String
+ val z: String
+
+ constructor(
+ x: String,
+ y: String,
+ z: String,) {
+ this.x = x
+ this.y = y
+ this.z = z
+ }
+}
+
+class D2 {
+ val x: String
+ val y: String
+ val z: String
+
+ constructor(
+ x: String,
+ y: String,
+ z: String
+ ,) {
+ this.x = x
+ this.y = y
+ this.z = z
+ }
+}
+
+class A3 {
+ val x: String
+
+ constructor(x: String,) {
+ this.x = x
+ }
+}
+
+class B3 {
+ val x: String
+
+ constructor(x: String) {
+ this.x = x
+ }
+}
+
+class C3 {
+ val x: String
+
+ constructor(
+ x: String,) {
+ this.x = x
+ }
+}
+
+class D3 {
+ val x: String
+
+ constructor(
+ x: String
+ ,) {
+ this.x = x
+ }
+}
+
+class E1 {
+ val x: String
+ val y: String
+ val z: String
+
+ constructor(
+ x: String,
+ y: String, z: String,) {
+ this.x = x
+ this.y = y
+ this.z = z
+ }
+}
+
+class E2 {
+ val x: String
+ val y: String
+ val z: String
+
+ constructor(
+ x: String,
+ y: String, z: String) {
+ this.x = x
+ this.y = y
+ this.z = z
+ }
+}
+
+// SET_TRUE: ALLOW_TRAILING_COMMA
\ No newline at end of file
diff --git a/idea/tests/org/jetbrains/kotlin/formatter/AbstractFormatterTest.java b/idea/tests/org/jetbrains/kotlin/formatter/AbstractFormatterTest.java
index 71fe797671e..cd8a865a686 100644
--- a/idea/tests/org/jetbrains/kotlin/formatter/AbstractFormatterTest.java
+++ b/idea/tests/org/jetbrains/kotlin/formatter/AbstractFormatterTest.java
@@ -22,6 +22,7 @@ import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.idea.KotlinLanguage;
+import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings;
import org.jetbrains.kotlin.idea.test.KotlinLightIdeaTestCase;
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase;
import org.jetbrains.kotlin.test.InTextDirectivesUtils;
@@ -139,6 +140,11 @@ public abstract class AbstractFormatterTest extends KotlinLightIdeaTestCase {
codeStyleSettings.setRightMargin(KotlinLanguage.INSTANCE, rightMargin);
}
+ Boolean trailingComma = InTextDirectivesUtils.getPrefixedBoolean(originalFileText, "// TRAILING_COMMA: ");
+ if (trailingComma != null) {
+ codeStyleSettings.getCustomSettings(KotlinCodeStyleSettings.class).ALLOW_TRAILING_COMMA = trailingComma;
+ }
+
SettingsConfigurator configurator = FormatSettingsUtil.createConfigurator(originalFileText, codeStyleSettings);
if (!inverted) {
configurator.configureSettings();
diff --git a/idea/tests/org/jetbrains/kotlin/formatter/FormatterTestGenerated.java b/idea/tests/org/jetbrains/kotlin/formatter/FormatterTestGenerated.java
index 5ebe220f0dd..b001edfa1f0 100644
--- a/idea/tests/org/jetbrains/kotlin/formatter/FormatterTestGenerated.java
+++ b/idea/tests/org/jetbrains/kotlin/formatter/FormatterTestGenerated.java
@@ -1151,6 +1151,52 @@ public class FormatterTestGenerated extends AbstractFormatterTest {
runTest("idea/testData/formatter/parameterList/ParameterListWrapAsNeeded.after.kt");
}
}
+
+ @TestMetadata("idea/testData/formatter/trailingComma")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class TrailingComma extends AbstractFormatterTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInTrailingComma() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/formatter/trailingComma"), Pattern.compile("^([^\\.]+)\\.after\\.kt.*$"), null, true);
+ }
+
+ @TestMetadata("idea/testData/formatter/trailingComma/valueParameters")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class ValueParameters extends AbstractFormatterTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInValueParameters() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/formatter/trailingComma/valueParameters"), Pattern.compile("^([^\\.]+)\\.after\\.kt.*$"), null, true);
+ }
+
+ @TestMetadata("Function.after.kt")
+ public void testFunction() throws Exception {
+ runTest("idea/testData/formatter/trailingComma/valueParameters/Function.after.kt");
+ }
+
+ @TestMetadata("OptionalTypes.after.kt")
+ public void testOptionalTypes() throws Exception {
+ runTest("idea/testData/formatter/trailingComma/valueParameters/OptionalTypes.after.kt");
+ }
+
+ @TestMetadata("PrimaryConstructor.after.kt")
+ public void testPrimaryConstructor() throws Exception {
+ runTest("idea/testData/formatter/trailingComma/valueParameters/PrimaryConstructor.after.kt");
+ }
+
+ @TestMetadata("SecondConstructor.after.kt")
+ public void testSecondConstructor() throws Exception {
+ runTest("idea/testData/formatter/trailingComma/valueParameters/SecondConstructor.after.kt");
+ }
+ }
+ }
}
@TestMetadata("idea/testData/formatter")
@@ -1516,5 +1562,51 @@ public class FormatterTestGenerated extends AbstractFormatterTest {
runTest("idea/testData/formatter/parameterList/DefaultParameterValues.after.inv.kt");
}
}
+
+ @TestMetadata("idea/testData/formatter/trailingComma")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class TrailingComma extends AbstractFormatterTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest(this::doTestInverted, this, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInTrailingComma() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/formatter/trailingComma"), Pattern.compile("^([^\\.]+)\\.after\\.inv\\.kt.*$"), null, true);
+ }
+
+ @TestMetadata("idea/testData/formatter/trailingComma/valueParameters")
+ @TestDataPath("$PROJECT_ROOT")
+ @RunWith(JUnit3RunnerWithInners.class)
+ public static class ValueParameters extends AbstractFormatterTest {
+ private void runTest(String testDataFilePath) throws Exception {
+ KotlinTestUtils.runTest(this::doTestInverted, this, testDataFilePath);
+ }
+
+ public void testAllFilesPresentInValueParameters() throws Exception {
+ KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/formatter/trailingComma/valueParameters"), Pattern.compile("^([^\\.]+)\\.after\\.inv\\.kt.*$"), null, true);
+ }
+
+ @TestMetadata("Function.after.inv.kt")
+ public void testFunction() throws Exception {
+ runTest("idea/testData/formatter/trailingComma/valueParameters/Function.after.inv.kt");
+ }
+
+ @TestMetadata("OptionalTypes.after.inv.kt")
+ public void testOptionalTypes() throws Exception {
+ runTest("idea/testData/formatter/trailingComma/valueParameters/OptionalTypes.after.inv.kt");
+ }
+
+ @TestMetadata("PrimaryConstructor.after.inv.kt")
+ public void testPrimaryConstructor() throws Exception {
+ runTest("idea/testData/formatter/trailingComma/valueParameters/PrimaryConstructor.after.inv.kt");
+ }
+
+ @TestMetadata("SecondConstructor.after.inv.kt")
+ public void testSecondConstructor() throws Exception {
+ runTest("idea/testData/formatter/trailingComma/valueParameters/SecondConstructor.after.inv.kt");
+ }
+ }
+ }
}
}