From fb26110f3143cfb6d5cf3f2f2ba54937148748c4 Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Fri, 17 Jun 2022 13:10:07 +0200 Subject: [PATCH] [kotlin] fix formatting for context receivers ^KTIJ-21346 fixed GitOrigin-RevId: 56a761537dfb37a6f739a17f76abc2f5b9126271 --- .../idea/formatter/KotlinCommonBlock.kt | 2 +- .../formatter/EnterHandlerTestGenerated.java | 48 +++++++++++++++++++ ...memberFunctionWithContextReceiver.after.kt | 4 ++ .../memberFunctionWithContextReceiver.kt | 3 ++ ...ionWithContextReceiverNoModifiers.after.kt | 4 ++ ...rFunctionWithContextReceiverNoModifiers.kt | 3 ++ ...memberPropertyWithContextReceiver.after.kt | 4 ++ .../memberPropertyWithContextReceiver.kt | 3 ++ ...rtyWithContextReceiverNoModifiers.after.kt | 4 ++ ...rPropertyWithContextReceiverNoModifiers.kt | 3 ++ ...pLevelFunctionWithContextReceiver.after.kt | 2 + .../topLevelFunctionWithContextReceiver.kt | 1 + ...ionWithContextReceiverNoModifiers.after.kt | 2 + ...lFunctionWithContextReceiverNoModifiers.kt | 1 + ...pLevelPropertyWithContextReceiver.after.kt | 2 + .../topLevelPropertyWithContextReceiver.kt | 1 + ...rtyWithContextReceiverNoModifiers.after.kt | 2 + ...lPropertyWithContextReceiverNoModifiers.kt | 1 + .../KotlinLangLineIndentProvider.kt | 26 ++++++++++ ...ormanceTypingIndentationTestGenerated.java | 48 +++++++++++++++++++ 20 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/memberFunctionWithContextReceiver.after.kt create mode 100644 plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/memberFunctionWithContextReceiver.kt create mode 100644 plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/memberFunctionWithContextReceiverNoModifiers.after.kt create mode 100644 plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/memberFunctionWithContextReceiverNoModifiers.kt create mode 100644 plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/memberPropertyWithContextReceiver.after.kt create mode 100644 plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/memberPropertyWithContextReceiver.kt create mode 100644 plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/memberPropertyWithContextReceiverNoModifiers.after.kt create mode 100644 plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/memberPropertyWithContextReceiverNoModifiers.kt create mode 100644 plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/topLevelFunctionWithContextReceiver.after.kt create mode 100644 plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/topLevelFunctionWithContextReceiver.kt create mode 100644 plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/topLevelFunctionWithContextReceiverNoModifiers.after.kt create mode 100644 plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/topLevelFunctionWithContextReceiverNoModifiers.kt create mode 100644 plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/topLevelPropertyWithContextReceiver.after.kt create mode 100644 plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/topLevelPropertyWithContextReceiver.kt create mode 100644 plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/topLevelPropertyWithContextReceiverNoModifiers.after.kt create mode 100644 plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/topLevelPropertyWithContextReceiverNoModifiers.kt diff --git a/plugins/kotlin/formatter/src/org/jetbrains/kotlin/idea/formatter/KotlinCommonBlock.kt b/plugins/kotlin/formatter/src/org/jetbrains/kotlin/idea/formatter/KotlinCommonBlock.kt index 2f43c66098af..26e4a9e3b397 100644 --- a/plugins/kotlin/formatter/src/org/jetbrains/kotlin/idea/formatter/KotlinCommonBlock.kt +++ b/plugins/kotlin/formatter/src/org/jetbrains/kotlin/idea/formatter/KotlinCommonBlock.kt @@ -1007,7 +1007,7 @@ private val INDENT_RULES = arrayOf( strategy("Indent for parts") .within(PROPERTY, FUN, DESTRUCTURING_DECLARATION, SECONDARY_CONSTRUCTOR) - .notForType(BLOCK, FUN_KEYWORD, VAL_KEYWORD, VAR_KEYWORD, CONSTRUCTOR_KEYWORD, RPAR, EOL_COMMENT) + .notForType(BLOCK, FUN_KEYWORD, VAL_KEYWORD, VAR_KEYWORD, CONSTRUCTOR_KEYWORD, RPAR, EOL_COMMENT, CONTEXT_RECEIVER_LIST, MODIFIER_LIST) .set(Indent.getContinuationWithoutFirstIndent()), strategy("Chained calls") diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/formatter/EnterHandlerTestGenerated.java b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/formatter/EnterHandlerTestGenerated.java index ce1fd3a3ee52..c89634e26b57 100644 --- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/formatter/EnterHandlerTestGenerated.java +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/formatter/EnterHandlerTestGenerated.java @@ -165,6 +165,54 @@ public abstract class EnterHandlerTestGenerated extends AbstractEnterHandlerTest } } + @RunWith(JUnit3RunnerWithInners.class) + @TestMetadata("testData/editor/enterHandler/contextReceivers") + public static class ContextReceivers extends AbstractEnterHandlerTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doNewlineTest, this, testDataFilePath); + } + + @TestMetadata("memberFunctionWithContextReceiver.after.kt") + public void testMemberFunctionWithContextReceiver() throws Exception { + runTest("testData/editor/enterHandler/contextReceivers/memberFunctionWithContextReceiver.after.kt"); + } + + @TestMetadata("memberFunctionWithContextReceiverNoModifiers.after.kt") + public void testMemberFunctionWithContextReceiverNoModifiers() throws Exception { + runTest("testData/editor/enterHandler/contextReceivers/memberFunctionWithContextReceiverNoModifiers.after.kt"); + } + + @TestMetadata("memberPropertyWithContextReceiver.after.kt") + public void testMemberPropertyWithContextReceiver() throws Exception { + runTest("testData/editor/enterHandler/contextReceivers/memberPropertyWithContextReceiver.after.kt"); + } + + @TestMetadata("memberPropertyWithContextReceiverNoModifiers.after.kt") + public void testMemberPropertyWithContextReceiverNoModifiers() throws Exception { + runTest("testData/editor/enterHandler/contextReceivers/memberPropertyWithContextReceiverNoModifiers.after.kt"); + } + + @TestMetadata("topLevelFunctionWithContextReceiver.after.kt") + public void testTopLevelFunctionWithContextReceiver() throws Exception { + runTest("testData/editor/enterHandler/contextReceivers/topLevelFunctionWithContextReceiver.after.kt"); + } + + @TestMetadata("topLevelFunctionWithContextReceiverNoModifiers.after.kt") + public void testTopLevelFunctionWithContextReceiverNoModifiers() throws Exception { + runTest("testData/editor/enterHandler/contextReceivers/topLevelFunctionWithContextReceiverNoModifiers.after.kt"); + } + + @TestMetadata("topLevelPropertyWithContextReceiver.after.kt") + public void testTopLevelPropertyWithContextReceiver() throws Exception { + runTest("testData/editor/enterHandler/contextReceivers/topLevelPropertyWithContextReceiver.after.kt"); + } + + @TestMetadata("topLevelPropertyWithContextReceiverNoModifiers.after.kt") + public void testTopLevelPropertyWithContextReceiverNoModifiers() throws Exception { + runTest("testData/editor/enterHandler/contextReceivers/topLevelPropertyWithContextReceiverNoModifiers.after.kt"); + } + } + @RunWith(JUnit3RunnerWithInners.class) @TestMetadata("testData/editor/enterHandler/controlFlowConstructions") public static class ControlFlowConstructions extends AbstractEnterHandlerTest { diff --git a/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/memberFunctionWithContextReceiver.after.kt b/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/memberFunctionWithContextReceiver.after.kt new file mode 100644 index 000000000000..c83516524b67 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/memberFunctionWithContextReceiver.after.kt @@ -0,0 +1,4 @@ +class C { + context(A) + private fun x() = Unit +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/memberFunctionWithContextReceiver.kt b/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/memberFunctionWithContextReceiver.kt new file mode 100644 index 000000000000..18727c30b775 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/memberFunctionWithContextReceiver.kt @@ -0,0 +1,3 @@ +class C { + context(A) private fun x() = Unit +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/memberFunctionWithContextReceiverNoModifiers.after.kt b/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/memberFunctionWithContextReceiverNoModifiers.after.kt new file mode 100644 index 000000000000..a4f8afccc0e4 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/memberFunctionWithContextReceiverNoModifiers.after.kt @@ -0,0 +1,4 @@ +class C { + context(A) + fun x() = Unit +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/memberFunctionWithContextReceiverNoModifiers.kt b/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/memberFunctionWithContextReceiverNoModifiers.kt new file mode 100644 index 000000000000..0213e3c968c7 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/memberFunctionWithContextReceiverNoModifiers.kt @@ -0,0 +1,3 @@ +class C { + context(A)fun x() = Unit +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/memberPropertyWithContextReceiver.after.kt b/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/memberPropertyWithContextReceiver.after.kt new file mode 100644 index 000000000000..a9ce75e0dde9 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/memberPropertyWithContextReceiver.after.kt @@ -0,0 +1,4 @@ +class C { + context(A) + private val x = 1 +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/memberPropertyWithContextReceiver.kt b/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/memberPropertyWithContextReceiver.kt new file mode 100644 index 000000000000..13ae8568c930 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/memberPropertyWithContextReceiver.kt @@ -0,0 +1,3 @@ +class C { + context(A) private val x = 1 +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/memberPropertyWithContextReceiverNoModifiers.after.kt b/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/memberPropertyWithContextReceiverNoModifiers.after.kt new file mode 100644 index 000000000000..e3af7f3a8b60 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/memberPropertyWithContextReceiverNoModifiers.after.kt @@ -0,0 +1,4 @@ +class C { + context(A) + val x = 1 +} diff --git a/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/memberPropertyWithContextReceiverNoModifiers.kt b/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/memberPropertyWithContextReceiverNoModifiers.kt new file mode 100644 index 000000000000..fda9df18a38c --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/memberPropertyWithContextReceiverNoModifiers.kt @@ -0,0 +1,3 @@ +class C { + context(A) val x = 1 +} \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/topLevelFunctionWithContextReceiver.after.kt b/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/topLevelFunctionWithContextReceiver.after.kt new file mode 100644 index 000000000000..169d481aae50 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/topLevelFunctionWithContextReceiver.after.kt @@ -0,0 +1,2 @@ +context(A) +private fun x() = Unit \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/topLevelFunctionWithContextReceiver.kt b/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/topLevelFunctionWithContextReceiver.kt new file mode 100644 index 000000000000..489b3bad374d --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/topLevelFunctionWithContextReceiver.kt @@ -0,0 +1 @@ +context(A) private fun x() = Unit \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/topLevelFunctionWithContextReceiverNoModifiers.after.kt b/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/topLevelFunctionWithContextReceiverNoModifiers.after.kt new file mode 100644 index 000000000000..cde118abe173 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/topLevelFunctionWithContextReceiverNoModifiers.after.kt @@ -0,0 +1,2 @@ +context(A) +fun x() = Unit diff --git a/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/topLevelFunctionWithContextReceiverNoModifiers.kt b/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/topLevelFunctionWithContextReceiverNoModifiers.kt new file mode 100644 index 000000000000..ee3786c9fe10 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/topLevelFunctionWithContextReceiverNoModifiers.kt @@ -0,0 +1 @@ +context(A) fun x() = Unit \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/topLevelPropertyWithContextReceiver.after.kt b/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/topLevelPropertyWithContextReceiver.after.kt new file mode 100644 index 000000000000..dc9e6966471f --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/topLevelPropertyWithContextReceiver.after.kt @@ -0,0 +1,2 @@ +context(A) +private val x = 1 \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/topLevelPropertyWithContextReceiver.kt b/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/topLevelPropertyWithContextReceiver.kt new file mode 100644 index 000000000000..3f0e4ad114d0 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/topLevelPropertyWithContextReceiver.kt @@ -0,0 +1 @@ +context(A) private val x = 1 \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/topLevelPropertyWithContextReceiverNoModifiers.after.kt b/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/topLevelPropertyWithContextReceiverNoModifiers.after.kt new file mode 100644 index 000000000000..58396b825ccd --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/topLevelPropertyWithContextReceiverNoModifiers.after.kt @@ -0,0 +1,2 @@ +context(A) +val x = 1 diff --git a/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/topLevelPropertyWithContextReceiverNoModifiers.kt b/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/topLevelPropertyWithContextReceiverNoModifiers.kt new file mode 100644 index 000000000000..1a442f79c073 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/editor/enterHandler/contextReceivers/topLevelPropertyWithContextReceiverNoModifiers.kt @@ -0,0 +1 @@ +context(A) val x = 1 \ No newline at end of file diff --git a/plugins/kotlin/line-indent-provider/src/org/jetbrains/kotlin/idea/formatter/lineIndent/KotlinLangLineIndentProvider.kt b/plugins/kotlin/line-indent-provider/src/org/jetbrains/kotlin/idea/formatter/lineIndent/KotlinLangLineIndentProvider.kt index ee27b5d2c6b1..8339d17e0336 100644 --- a/plugins/kotlin/line-indent-provider/src/org/jetbrains/kotlin/idea/formatter/lineIndent/KotlinLangLineIndentProvider.kt +++ b/plugins/kotlin/line-indent-provider/src/org/jetbrains/kotlin/idea/formatter/lineIndent/KotlinLangLineIndentProvider.kt @@ -118,6 +118,10 @@ abstract class KotlinLangLineIndentProvider : JavaLikeLangLineIndentProvider() { return factory.createIndentCalculator(indent, it.startOffset) } + findContextReceiverListBefore(before)?.let { + return factory.createIndentCalculator(Indent.getNoneIndent(), it.startOffset) + } + return before.controlFlowStatementBefore()?.let { controlFlowKeywordPosition -> val indent = when { controlFlowKeywordPosition.similarToCatchKeyword() -> if (before.isAt(RightParenthesis)) Indent.getNoneIndent() else Indent.getNormalIndent() @@ -326,6 +330,28 @@ abstract class KotlinLangLineIndentProvider : JavaLikeLangLineIndentProvider() { } } + /** + * ``` + * context(A) fun x() + * ``` + */ + private fun findContextReceiverListBefore(before: SemanticEditorPosition): SemanticEditorPosition? { + if (!before.isAt(RightParenthesis)) return null + + val probableContextReceiverKeyword = before.copy().apply { + moveBeforeParentheses(LeftParenthesis, RightParenthesis) + } + + if (probableContextReceiverKeyword.isAt(Identifier) + && probableContextReceiverKeyword.after().isAt(LeftParenthesis) + && probableContextReceiverKeyword.textOfCurrentPosition() == KtTokens.CONTEXT_KEYWORD.value + ) { + return probableContextReceiverKeyword + } + return null + } + + /** * @param endOfDeclaration is position before '=' for expression body or '{' for block body */ diff --git a/plugins/kotlin/performance-tests/test/org/jetbrains/kotlin/idea/perf/synthetic/PerformanceTypingIndentationTestGenerated.java b/plugins/kotlin/performance-tests/test/org/jetbrains/kotlin/idea/perf/synthetic/PerformanceTypingIndentationTestGenerated.java index e805933e5bcc..9e513a4d765a 100644 --- a/plugins/kotlin/performance-tests/test/org/jetbrains/kotlin/idea/perf/synthetic/PerformanceTypingIndentationTestGenerated.java +++ b/plugins/kotlin/performance-tests/test/org/jetbrains/kotlin/idea/perf/synthetic/PerformanceTypingIndentationTestGenerated.java @@ -165,6 +165,54 @@ public abstract class PerformanceTypingIndentationTestGenerated extends Abstract } } + @RunWith(JUnit3RunnerWithInners.class) + @TestMetadata("../idea/tests/testData/editor/enterHandler/contextReceivers") + public static class ContextReceivers extends AbstractPerformanceTypingIndentationTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doNewlineTest, this, testDataFilePath); + } + + @TestMetadata("memberFunctionWithContextReceiver.after.kt") + public void testMemberFunctionWithContextReceiver() throws Exception { + runTest("../idea/tests/testData/editor/enterHandler/contextReceivers/memberFunctionWithContextReceiver.after.kt"); + } + + @TestMetadata("memberFunctionWithContextReceiverNoModifiers.after.kt") + public void testMemberFunctionWithContextReceiverNoModifiers() throws Exception { + runTest("../idea/tests/testData/editor/enterHandler/contextReceivers/memberFunctionWithContextReceiverNoModifiers.after.kt"); + } + + @TestMetadata("memberPropertyWithContextReceiver.after.kt") + public void testMemberPropertyWithContextReceiver() throws Exception { + runTest("../idea/tests/testData/editor/enterHandler/contextReceivers/memberPropertyWithContextReceiver.after.kt"); + } + + @TestMetadata("memberPropertyWithContextReceiverNoModifiers.after.kt") + public void testMemberPropertyWithContextReceiverNoModifiers() throws Exception { + runTest("../idea/tests/testData/editor/enterHandler/contextReceivers/memberPropertyWithContextReceiverNoModifiers.after.kt"); + } + + @TestMetadata("topLevelFunctionWithContextReceiver.after.kt") + public void testTopLevelFunctionWithContextReceiver() throws Exception { + runTest("../idea/tests/testData/editor/enterHandler/contextReceivers/topLevelFunctionWithContextReceiver.after.kt"); + } + + @TestMetadata("topLevelFunctionWithContextReceiverNoModifiers.after.kt") + public void testTopLevelFunctionWithContextReceiverNoModifiers() throws Exception { + runTest("../idea/tests/testData/editor/enterHandler/contextReceivers/topLevelFunctionWithContextReceiverNoModifiers.after.kt"); + } + + @TestMetadata("topLevelPropertyWithContextReceiver.after.kt") + public void testTopLevelPropertyWithContextReceiver() throws Exception { + runTest("../idea/tests/testData/editor/enterHandler/contextReceivers/topLevelPropertyWithContextReceiver.after.kt"); + } + + @TestMetadata("topLevelPropertyWithContextReceiverNoModifiers.after.kt") + public void testTopLevelPropertyWithContextReceiverNoModifiers() throws Exception { + runTest("../idea/tests/testData/editor/enterHandler/contextReceivers/topLevelPropertyWithContextReceiverNoModifiers.after.kt"); + } + } + @RunWith(JUnit3RunnerWithInners.class) @TestMetadata("../idea/tests/testData/editor/enterHandler/controlFlowConstructions") public static class ControlFlowConstructions extends AbstractPerformanceTypingIndentationTest {