From 07bda5a7597e10269d22b90be4eea0ca18740e35 Mon Sep 17 00:00:00 2001 From: Dmitry Gridin Date: Thu, 26 Dec 2019 20:21:02 +0700 Subject: [PATCH] Formatter: support trailing comma in collection literal expression #KT-34744 --- .../idea/formatter/KotlinCommonBlock.kt | 17 +- .../TrailingCommaPostFormatProcessor.kt | 4 + idea/testData/formatter/ArrayLiteral.after.kt | 2 +- ...CollectionLiteralInAnnotation.after.inv.kt | 131 ++++++++++++ .../CollectionLiteralInAnnotation.after.kt | 196 ++++++++++++++++++ .../CollectionLiteralInAnnotation.kt | 114 ++++++++++ .../formatter/FormatterTestGenerated.java | 36 ++++ 7 files changed, 490 insertions(+), 10 deletions(-) create mode 100644 idea/testData/formatter/trailingComma/collectionLiteralExpression/CollectionLiteralInAnnotation.after.inv.kt create mode 100644 idea/testData/formatter/trailingComma/collectionLiteralExpression/CollectionLiteralInAnnotation.after.kt create mode 100644 idea/testData/formatter/trailingComma/collectionLiteralExpression/CollectionLiteralInAnnotation.kt 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 727f1f66659..411af9aa07e 100644 --- a/idea/formatter/src/org/jetbrains/kotlin/idea/formatter/KotlinCommonBlock.kt +++ b/idea/formatter/src/org/jetbrains/kotlin/idea/formatter/KotlinCommonBlock.kt @@ -611,17 +611,13 @@ abstract class KotlinCommonBlock( ) } - elementType === INDICES -> return { childElement -> - trailingCommaWrappingStrategyWithMultiLineCheck(LBRACKET, RBRACKET)(childElement) - } + elementType === INDICES -> return defaultTrailingCommaWrappingStrategy(LBRACKET, RBRACKET) - elementType === TYPE_PARAMETER_LIST -> return { childElement -> - trailingCommaWrappingStrategyWithMultiLineCheck(LT, GT)(childElement) - } + elementType === TYPE_PARAMETER_LIST -> return defaultTrailingCommaWrappingStrategy(LT, GT) - elementType === TYPE_ARGUMENT_LIST -> return { childElement -> - trailingCommaWrappingStrategyWithMultiLineCheck(LT, GT)(childElement) - } + elementType === TYPE_ARGUMENT_LIST -> return defaultTrailingCommaWrappingStrategy(LT, GT) + + elementType === COLLECTION_LITERAL_EXPRESSION -> return defaultTrailingCommaWrappingStrategy(LBRACKET, RBRACKET) elementType === SUPER_TYPE_LIST -> { val wrap = Wrap.createWrap(commonSettings.EXTENDS_LIST_WRAP, false) @@ -719,6 +715,9 @@ abstract class KotlinCommonBlock( return ::noWrapping } + private fun defaultTrailingCommaWrappingStrategy(leftAnchor: IElementType, rightAnchor: IElementType): WrappingStrategy = + fun(childElement: ASTNode): Wrap? = trailingCommaWrappingStrategyWithMultiLineCheck(leftAnchor, rightAnchor)(childElement) + private val ASTNode.withTrailingComma: Boolean get() = when { lastChildNode?.let { getPrevWithoutWhitespaceAndComments(it) }?.elementType === COMMA -> true diff --git a/idea/src/org/jetbrains/kotlin/idea/formatter/TrailingCommaPostFormatProcessor.kt b/idea/src/org/jetbrains/kotlin/idea/formatter/TrailingCommaPostFormatProcessor.kt index 47f04368e4c..0f2b3611d76 100644 --- a/idea/src/org/jetbrains/kotlin/idea/formatter/TrailingCommaPostFormatProcessor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/formatter/TrailingCommaPostFormatProcessor.kt @@ -54,6 +54,10 @@ private class TrailingCommaVisitor(val settings: CodeStyleSettings) : KtTreeVisi super.visitTypeArgumentList(typeArgumentList) } + override fun visitCollectionLiteralExpression(expression: KtCollectionLiteralExpression) = processCommaOwnerIfInRange(expression) { + super.visitCollectionLiteralExpression(expression) + } + private fun processCommaOwnerIfInRange(element: KtElement, preHook: () -> Unit = {}) { if (myPostProcessor.isElementPartlyInRange(element)) { preHook() diff --git a/idea/testData/formatter/ArrayLiteral.after.kt b/idea/testData/formatter/ArrayLiteral.after.kt index a40d6e48f43..363b3e328ae 100644 --- a/idea/testData/formatter/ArrayLiteral.after.kt +++ b/idea/testData/formatter/ArrayLiteral.after.kt @@ -2,6 +2,6 @@ modules = [ AppModule::class, DataModule::class, - DomainModule::class + DomainModule::class, ], ) \ No newline at end of file diff --git a/idea/testData/formatter/trailingComma/collectionLiteralExpression/CollectionLiteralInAnnotation.after.inv.kt b/idea/testData/formatter/trailingComma/collectionLiteralExpression/CollectionLiteralInAnnotation.after.inv.kt new file mode 100644 index 00000000000..3d389d5964d --- /dev/null +++ b/idea/testData/formatter/trailingComma/collectionLiteralExpression/CollectionLiteralInAnnotation.after.inv.kt @@ -0,0 +1,131 @@ +// SET_TRUE: ALLOW_TRAILING_COMMA + +@Anno([1]) +fun a() = Unit + +@Anno([ + 1, +]) +fun a() = Unit + +@Anno([1 +]) +fun a() = Unit + +@Anno([ + 1, +]) +fun a() = Unit + +@Anno([ + 1]) +fun a() = Unit + +@Anno([1, 2]) +fun a() = Unit + +@Anno([ + 1, 2, +]) +fun a() = Unit + +@Anno([1, 2 +]) +fun a() = Unit + +@Anno([ + 1, 2, +]) +fun a() = Unit + +@Anno([ + 1, 2]) +fun a() = Unit + +@Anno([1, 2, 2]) +fun a() = Unit + +@Anno([ + 1, 2, 2, +]) +fun a() = Unit + +@Anno(["1" +]) +fun a() = Unit + +@Anno([ + 1, +]) +fun a() = Unit + +@Anno([ + 1, 2, 2]) +fun a() = Unit + +@Anno([1/* + */]) +fun a() = Unit + +@Anno([ + 1, //dw +]) +fun a() = Unit + +@Anno([1 // ds +]) +fun a() = Unit + +@Anno([ +/* + */ + // d + 1,/* + *//* + */ +]) +fun a() = Unit + +@Anno([ + /* +*/ 1]) +fun a() = Unit + +@Anno([1/* + */, 2]) +fun a() = Unit + +@Anno([ + 1, + 2/* + */,/* + */ +]) +fun a() = Unit + +@Anno([/* + */1, 2 +]) +fun a() = Unit + +@Anno(["1" +]) +fun a() = Unit + +@Anno([ + 1, +]) +fun a() = Unit + +@Anno([ + 1, 2 /* + */]) +fun a() = Unit + +@Component( + modules = [ + AppModule::class, DataModule::class, + DomainModule::class + ], +) +fun b() = Unit \ No newline at end of file diff --git a/idea/testData/formatter/trailingComma/collectionLiteralExpression/CollectionLiteralInAnnotation.after.kt b/idea/testData/formatter/trailingComma/collectionLiteralExpression/CollectionLiteralInAnnotation.after.kt new file mode 100644 index 00000000000..1071b7e82db --- /dev/null +++ b/idea/testData/formatter/trailingComma/collectionLiteralExpression/CollectionLiteralInAnnotation.after.kt @@ -0,0 +1,196 @@ +// SET_TRUE: ALLOW_TRAILING_COMMA + +@Anno([1]) +fun a() = Unit + +@Anno( + [ + 1, + ], +) +fun a() = Unit + +@Anno( + [ + 1, + ], +) +fun a() = Unit + +@Anno( + [ + 1, + ], +) +fun a() = Unit + +@Anno( + [ + 1, + ], +) +fun a() = Unit + +@Anno([1, 2]) +fun a() = Unit + +@Anno( + [ + 1, 2, + ], +) +fun a() = Unit + +@Anno( + [ + 1, 2, + ], +) +fun a() = Unit + +@Anno( + [ + 1, 2, + ], +) +fun a() = Unit + +@Anno( + [ + 1, 2, + ], +) +fun a() = Unit + +@Anno([1, 2, 2]) +fun a() = Unit + +@Anno( + [ + 1, 2, 2, + ], +) +fun a() = Unit + +@Anno( + [ + "1", + ], +) +fun a() = Unit + +@Anno( + [ + 1, + ], +) +fun a() = Unit + +@Anno( + [ + 1, 2, 2, + ], +) +fun a() = Unit + +@Anno( + [ + 1,/* + */ + ], +) +fun a() = Unit + +@Anno( + [ + 1, //dw + ], +) +fun a() = Unit + +@Anno( + [ + 1, // ds + ], +) +fun a() = Unit + +@Anno( + [ +/* + */ + // d + 1,/* + *//* + */ + ], +) +fun a() = Unit + +@Anno( + [ + /* + */ + 1, + ], +) +fun a() = Unit + +@Anno( + [ + 1,/* + */ + 2, + ], +) +fun a() = Unit + +@Anno( + [ + 1, + 2/* + */,/* + */ + ], +) +fun a() = Unit + +@Anno( + [ +/* + */ + 1, 2, + ], +) +fun a() = Unit + +@Anno( + [ + "1", + ], +) +fun a() = Unit + +@Anno( + [ + 1, + ], +) +fun a() = Unit + +@Anno( + [ + 1, + 2, /* + */ + ], +) +fun a() = Unit + +@Component( + modules = [ + AppModule::class, DataModule::class, + DomainModule::class, + ], +) +fun b() = Unit \ No newline at end of file diff --git a/idea/testData/formatter/trailingComma/collectionLiteralExpression/CollectionLiteralInAnnotation.kt b/idea/testData/formatter/trailingComma/collectionLiteralExpression/CollectionLiteralInAnnotation.kt new file mode 100644 index 00000000000..02aeb8f86ef --- /dev/null +++ b/idea/testData/formatter/trailingComma/collectionLiteralExpression/CollectionLiteralInAnnotation.kt @@ -0,0 +1,114 @@ +// SET_TRUE: ALLOW_TRAILING_COMMA + +@Anno([1]) +fun a() = Unit + +@Anno([1,]) +fun a() = Unit + +@Anno([1 + ]) +fun a() = Unit + +@Anno([ + 1, ]) +fun a() = Unit + +@Anno([ + 1 ]) +fun a() = Unit + +@Anno([1,2]) +fun a() = Unit + +@Anno([1, 2,]) +fun a() = Unit + +@Anno([1, 2 + ]) +fun a() = Unit + +@Anno([ + 1, 2, ]) +fun a() = Unit + +@Anno([ + 1, 2 ]) +fun a() = Unit + +@Anno([1, 2, 2]) +fun a() = Unit + +@Anno([1, 2, 2,]) +fun a() = Unit + +@Anno(["1" + ]) +fun a() = Unit + +@Anno([ + 1, ]) +fun a() = Unit + +@Anno([ + 1 , 2 , 2 ]) +fun a() = Unit + +@Anno([1/* + */]) +fun a() = Unit + +@Anno([1, //dw + ]) +fun a() = Unit + +@Anno([1 // ds + ]) +fun a() = Unit + +@Anno([/* + */ // d + 1/* + */,/* + */ ]) +fun a() = Unit + +@Anno([ + /* + */ 1 ]) +fun a() = Unit + +@Anno([1/* + */,2]) +fun a() = Unit + +@Anno([1, 2/* + */,/* + */]) +fun a() = Unit + +@Anno([/* + */1, 2 + ]) +fun a() = Unit + +@Anno(["1" + ]) +fun a() = Unit + +@Anno([ + 1, ]) +fun a() = Unit + +@Anno([ + 1 , 2 /* + */ ]) +fun a() = Unit + +@Component( + modules = [ + AppModule::class, DataModule::class, + DomainModule::class + ], +) +fun b() = Unit \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/formatter/FormatterTestGenerated.java b/idea/tests/org/jetbrains/kotlin/formatter/FormatterTestGenerated.java index db5bbcf2858..6745d9e8b13 100644 --- a/idea/tests/org/jetbrains/kotlin/formatter/FormatterTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/formatter/FormatterTestGenerated.java @@ -1164,6 +1164,24 @@ public class FormatterTestGenerated extends AbstractFormatterTest { KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/formatter/trailingComma"), Pattern.compile("^([^\\.]+)\\.after\\.kt.*$"), null, true); } + @TestMetadata("idea/testData/formatter/trailingComma/collectionLiteralExpression") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class CollectionLiteralExpression extends AbstractFormatterTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInCollectionLiteralExpression() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/formatter/trailingComma/collectionLiteralExpression"), Pattern.compile("^([^\\.]+)\\.after\\.kt.*$"), null, true); + } + + @TestMetadata("CollectionLiteralInAnnotation.after.kt") + public void testCollectionLiteralInAnnotation() throws Exception { + runTest("idea/testData/formatter/trailingComma/collectionLiteralExpression/CollectionLiteralInAnnotation.after.kt"); + } + } + @TestMetadata("idea/testData/formatter/trailingComma/indices") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -1662,6 +1680,24 @@ public class FormatterTestGenerated extends AbstractFormatterTest { KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/formatter/trailingComma"), Pattern.compile("^([^\\.]+)\\.after\\.inv\\.kt.*$"), null, true); } + @TestMetadata("idea/testData/formatter/trailingComma/collectionLiteralExpression") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class CollectionLiteralExpression extends AbstractFormatterTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTestInverted, this, testDataFilePath); + } + + public void testAllFilesPresentInCollectionLiteralExpression() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/formatter/trailingComma/collectionLiteralExpression"), Pattern.compile("^([^\\.]+)\\.after\\.inv\\.kt.*$"), null, true); + } + + @TestMetadata("CollectionLiteralInAnnotation.after.inv.kt") + public void testCollectionLiteralInAnnotation() throws Exception { + runTest("idea/testData/formatter/trailingComma/collectionLiteralExpression/CollectionLiteralInAnnotation.after.inv.kt"); + } + } + @TestMetadata("idea/testData/formatter/trailingComma/indices") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)