From 13ae4a28a8799ff21372042ee060f2a08956244c Mon Sep 17 00:00:00 2001 From: Dmitry Gridin Date: Wed, 18 Dec 2019 21:01:08 +0700 Subject: [PATCH] Formatter: support trailing comma in value parameters #KT-34744 --- .../formatter/KotlinCodeStyleSettings.java | 6 +- .../idea/formatter/KotlinCommonBlock.kt | 17 +- .../idea/formatter/kotlinSpacingRules.kt | 3 +- .../kotlin/idea/util/FormatterUtil.kt | 24 ++- idea/resources/META-INF/plugin-common.xml | 1 + ...KotlinLanguageCodeStyleSettingsProvider.kt | 4 +- .../TrailingCommaPostFormatProcessor.kt | 77 ++++++++ .../BlankLinesAfterClassHeader.after.kt | 2 +- ...ontinuationIndentInParameterLists.after.kt | 2 +- .../FunctionDefParametersAlign.after.kt | 4 +- .../formatter/FunctionDefParametersAlign.kt | 4 +- .../formatter/FunctionExpression.after.kt | 6 +- .../LineBreakBeforeExtendsColon.after.kt | 2 +- .../LineBreakBeforeExtendsColonWrap.after.kt | 2 +- .../MethodLParenthOnNextLine.after.inv.kt | 1 + .../MethodLParenthOnNextLine.after.kt | 1 + .../formatter/MethodLParenthOnNextLine.kt | 1 + .../MethodRParenthOnNextLine.after.inv.kt | 1 + .../MethodRParenthOnNextLine.after.kt | 1 + .../formatter/MethodRParenthOnNextLine.kt | 1 + .../formatter/NewLineForRBrace.after.kt | 4 +- idea/testData/formatter/NewLineForRBrace.kt | 4 +- .../ParameterAnnotationWrap.after.kt | 3 +- .../formatter/ParameterDocComments.after.kt | 5 +- .../formatter/Parameters.after.inv.kt | 2 +- idea/testData/formatter/Parameters.after.kt | 2 +- .../RightBracketOnNewLine.after.inv.kt | 3 +- .../formatter/RightBracketOnNewLine.after.kt | 3 +- .../formatter/RightBracketOnNewLine.kt | 3 +- idea/testData/formatter/ValVarSpaces.after.kt | 4 +- idea/testData/formatter/ValVarSpaces.kt | 4 +- idea/testData/formatter/WhereClause.after.kt | 2 +- .../DefaultParameterValues.after.inv.kt | 4 +- .../DefaultParameterValues.after.kt | 4 +- .../ParameterListChopAsNeeded.after.kt | 30 ++- .../ParameterListWrapAlways.after.kt | 45 +++-- .../ParameterListWrapAsNeeded.after.kt | 39 ++-- .../valueParameters/Function.after.inv.kt | 85 ++++++++ .../valueParameters/Function.after.kt | 85 ++++++++ .../trailingComma/valueParameters/Function.kt | 81 ++++++++ .../OptionalTypes.after.inv.kt | 75 +++++++ .../valueParameters/OptionalTypes.after.kt | 75 +++++++ .../valueParameters/OptionalTypes.kt | 69 +++++++ .../PrimaryConstructor.after.inv.kt | 94 +++++++++ .../PrimaryConstructor.after.kt | 94 +++++++++ .../valueParameters/PrimaryConstructor.kt | 90 +++++++++ .../SecondConstructor.after.inv.kt | 184 +++++++++++++++++ .../SecondConstructor.after.kt | 185 ++++++++++++++++++ .../valueParameters/SecondConstructor.kt | 178 +++++++++++++++++ .../formatter/AbstractFormatterTest.java | 6 + .../formatter/FormatterTestGenerated.java | 92 +++++++++ 51 files changed, 1644 insertions(+), 70 deletions(-) create mode 100644 idea/src/org/jetbrains/kotlin/idea/formatter/TrailingCommaPostFormatProcessor.kt create mode 100644 idea/testData/formatter/trailingComma/valueParameters/Function.after.inv.kt create mode 100644 idea/testData/formatter/trailingComma/valueParameters/Function.after.kt create mode 100644 idea/testData/formatter/trailingComma/valueParameters/Function.kt create mode 100644 idea/testData/formatter/trailingComma/valueParameters/OptionalTypes.after.inv.kt create mode 100644 idea/testData/formatter/trailingComma/valueParameters/OptionalTypes.after.kt create mode 100644 idea/testData/formatter/trailingComma/valueParameters/OptionalTypes.kt create mode 100644 idea/testData/formatter/trailingComma/valueParameters/PrimaryConstructor.after.inv.kt create mode 100644 idea/testData/formatter/trailingComma/valueParameters/PrimaryConstructor.after.kt create mode 100644 idea/testData/formatter/trailingComma/valueParameters/PrimaryConstructor.kt create mode 100644 idea/testData/formatter/trailingComma/valueParameters/SecondConstructor.after.inv.kt create mode 100644 idea/testData/formatter/trailingComma/valueParameters/SecondConstructor.after.kt create mode 100644 idea/testData/formatter/trailingComma/valueParameters/SecondConstructor.kt 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"); + } + } + } } }