From 51678d0a4549559a8c10408cdca0b2cfdff692d3 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Fri, 26 Dec 2014 20:25:00 +0300 Subject: [PATCH] KT-5874 Support code completion of label names after "continue@" and "break@" #KT-5874 Fixed --- .../plugin/completion/CompletionSession.kt | 9 ++++- .../jet/plugin/completion/CompletionUtils.kt | 23 ++++++++++++ .../completion/handlers/keywords/Break.kt | 4 +- .../handlers/keywords/Break.kt.after | 4 +- .../completion/keywords/BreakContinue.kt | 21 +++++++++++ .../completion/keywords/BreakWithLabel.kt | 17 +++++++++ .../completion/keywords/ContinueWithLabel.kt | 17 +++++++++ .../completion/keywords/InArgumentList.kt | 4 +- .../completion/keywords/InCodeBlock.kt | 4 +- .../keywords/InFunctionExpressionBody.kt | 4 +- .../keywords/InGetterExpressionBody.kt | 4 +- .../keywords/InParameterDefaultValue.kt | 4 +- .../keywords/InPropertyInitializer.kt | 4 +- idea/testData/completion/keywords/NoBreak1.kt | 14 +++++++ idea/testData/completion/keywords/NoBreak2.kt | 12 ++++++ .../completion/keywords/NoContinue.kt | 14 +++++++ .../basic/PropertiesBeforeKeywords.kt | 6 ++- .../KeywordCompletionTestGenerated.java | 37 ++++++++++++++++++- 18 files changed, 178 insertions(+), 24 deletions(-) create mode 100644 idea/testData/completion/keywords/BreakContinue.kt create mode 100644 idea/testData/completion/keywords/BreakWithLabel.kt create mode 100644 idea/testData/completion/keywords/ContinueWithLabel.kt create mode 100644 idea/testData/completion/keywords/NoBreak1.kt create mode 100644 idea/testData/completion/keywords/NoBreak2.kt create mode 100644 idea/testData/completion/keywords/NoContinue.kt diff --git a/idea/src/org/jetbrains/jet/plugin/completion/CompletionSession.kt b/idea/src/org/jetbrains/jet/plugin/completion/CompletionSession.kt index 1f4b050cdd9..1f5be276588 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/CompletionSession.kt +++ b/idea/src/org/jetbrains/jet/plugin/completion/CompletionSession.kt @@ -234,7 +234,8 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration, val ampIndex = prefix.indexOf("@") val keywordsPrefix = if (ampIndex < 0) prefix else prefix.substring(0, ampIndex) // if there is '@' in the prefix - use shorter prefix to not loose 'this' etc KeywordCompletion.complete(expression ?: parameters.getPosition(), keywordsPrefix) { lookupElement -> - when (lookupElement.getLookupString()) { + val keyword = lookupElement.getLookupString() + when (keyword) { // if "this" is parsed correctly in the current context - insert it and all this@xxx items "this" -> { if (expression != null) { @@ -249,6 +250,12 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration, } } + "break", "continue" -> { + if (expression != null) { + collector.addElements(breakOrContinueExpressionItems(expression, keyword)) + } + } + else -> collector.addElement(lookupElement) } } diff --git a/idea/src/org/jetbrains/jet/plugin/completion/CompletionUtils.kt b/idea/src/org/jetbrains/jet/plugin/completion/CompletionUtils.kt index 15c310008f4..d8d35dc52d3 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/CompletionUtils.kt +++ b/idea/src/org/jetbrains/jet/plugin/completion/CompletionUtils.kt @@ -65,6 +65,7 @@ import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor import org.jetbrains.jet.lang.psi.JetDeclarationWithBody import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns import org.jetbrains.jet.plugin.completion.handlers.WithTailInsertHandler +import org.jetbrains.jet.lang.psi.JetLoopExpression enum class ItemPriority { MULTIPLE_ARGUMENTS_ITEM @@ -333,3 +334,25 @@ private fun createKeywordWithLabelElement(keyword: String, label: String?): Look } return element } + +fun breakOrContinueExpressionItems(position: JetElement, breakOrContinue: String): Collection { + val result = ArrayList() + for (parent in position.parents()) { + when (parent) { + is JetLoopExpression -> { + if (result.isEmpty()) { + result.add(createKeywordWithLabelElement(breakOrContinue, null)) + } + + val label = (parent.getParent() as? JetLabeledExpression)?.getLabelName() + if (label != null) { + result.add(createKeywordWithLabelElement(breakOrContinue, label)) + } + } + + is JetDeclarationWithBody -> break //TODO: support non-local break's&continue's when they are supported by compiler + } + } + return result +} + diff --git a/idea/testData/completion/handlers/keywords/Break.kt b/idea/testData/completion/handlers/keywords/Break.kt index 0c592e98d5e..2ff4566f4b2 100644 --- a/idea/testData/completion/handlers/keywords/Break.kt +++ b/idea/testData/completion/handlers/keywords/Break.kt @@ -1,3 +1,5 @@ fun t() { - brea + while (true) { + brea + } } \ No newline at end of file diff --git a/idea/testData/completion/handlers/keywords/Break.kt.after b/idea/testData/completion/handlers/keywords/Break.kt.after index 2a0482cbb7e..b907313bc9f 100644 --- a/idea/testData/completion/handlers/keywords/Break.kt.after +++ b/idea/testData/completion/handlers/keywords/Break.kt.after @@ -1,3 +1,5 @@ fun t() { - break + while (true) { + break + } } \ No newline at end of file diff --git a/idea/testData/completion/keywords/BreakContinue.kt b/idea/testData/completion/keywords/BreakContinue.kt new file mode 100644 index 00000000000..16593ad273d --- /dev/null +++ b/idea/testData/completion/keywords/BreakContinue.kt @@ -0,0 +1,21 @@ +fun foo() { + @myFor + for (i in 1..10) { + @myWhile + while (x()) { + @myDo + do { + + } while (y()) + } + } +} + +// EXIST: { lookupString: "break", itemText: "break", tailText: null, attributes: "bold" } +// EXIST: { lookupString: "continue", itemText: "continue", tailText: null, attributes: "bold" } +// EXIST: { lookupString: "break@myDo", itemText: "break", tailText: "@myDo", attributes: "bold" } +// EXIST: { lookupString: "continue@myDo", itemText: "continue", tailText: "@myDo", attributes: "bold" } +// EXIST: { lookupString: "break@myWhile", itemText: "break", tailText: "@myWhile", attributes: "bold" } +// EXIST: { lookupString: "continue@myWhile", itemText: "continue", tailText: "@myWhile", attributes: "bold" } +// EXIST: { lookupString: "break@myFor", itemText: "break", tailText: "@myFor", attributes: "bold" } +// EXIST: { lookupString: "continue@myFor", itemText: "continue", tailText: "@myFor", attributes: "bold" } diff --git a/idea/testData/completion/keywords/BreakWithLabel.kt b/idea/testData/completion/keywords/BreakWithLabel.kt new file mode 100644 index 00000000000..22dfc19a15f --- /dev/null +++ b/idea/testData/completion/keywords/BreakWithLabel.kt @@ -0,0 +1,17 @@ +fun foo() { + @myFor + for (i in 1..10) { + @myWhile + while (x()) { + @myDo + do { + break@ + } while (y()) + } + } +} + +// EXIST: { lookupString: "break@myDo", itemText: "break", tailText: "@myDo", attributes: "bold" } +// EXIST: { lookupString: "break@myWhile", itemText: "break", tailText: "@myWhile", attributes: "bold" } +// EXIST: { lookupString: "break@myFor", itemText: "break", tailText: "@myFor", attributes: "bold" } +// NUMBER: 3 \ No newline at end of file diff --git a/idea/testData/completion/keywords/ContinueWithLabel.kt b/idea/testData/completion/keywords/ContinueWithLabel.kt new file mode 100644 index 00000000000..280020f8f5e --- /dev/null +++ b/idea/testData/completion/keywords/ContinueWithLabel.kt @@ -0,0 +1,17 @@ +fun foo() { + @myFor + for (i in 1..10) { + @myWhile + while (x()) { + @myDo + do { + continue@ + } while (y()) + } + } +} + +// EXIST: { lookupString: "continue@myDo", itemText: "continue", tailText: "@myDo", attributes: "bold" } +// EXIST: { lookupString: "continue@myWhile", itemText: "continue", tailText: "@myWhile", attributes: "bold" } +// EXIST: { lookupString: "continue@myFor", itemText: "continue", tailText: "@myFor", attributes: "bold" } +// NUMBER: 3 \ No newline at end of file diff --git a/idea/testData/completion/keywords/InArgumentList.kt b/idea/testData/completion/keywords/InArgumentList.kt index fc78f8d63b3..30f1fb3cace 100644 --- a/idea/testData/completion/keywords/InArgumentList.kt +++ b/idea/testData/completion/keywords/InArgumentList.kt @@ -5,8 +5,6 @@ fun foo(p: Int) { z() } -// EXIST: break -// EXIST: continue // EXIST: do // EXIST: false // EXIST: for @@ -21,4 +19,4 @@ fun foo(p: Int) { // EXIST: try // EXIST: when // EXIST: while -// NUMBER: 16 +// NUMBER: 14 diff --git a/idea/testData/completion/keywords/InCodeBlock.kt b/idea/testData/completion/keywords/InCodeBlock.kt index d3491428a7e..1c03bde1ebc 100644 --- a/idea/testData/completion/keywords/InCodeBlock.kt +++ b/idea/testData/completion/keywords/InCodeBlock.kt @@ -2,9 +2,7 @@ fun foo() { } -// EXIST: break // EXIST: class -// EXIST: continue // EXIST: do // EXIST: false // EXIST: for @@ -23,4 +21,4 @@ fun foo() { // EXIST: var // EXIST: when // EXIST: while -// NUMBER: 21 +// NUMBER: 19 diff --git a/idea/testData/completion/keywords/InFunctionExpressionBody.kt b/idea/testData/completion/keywords/InFunctionExpressionBody.kt index 5ba3c549c7d..21715926585 100644 --- a/idea/testData/completion/keywords/InFunctionExpressionBody.kt +++ b/idea/testData/completion/keywords/InFunctionExpressionBody.kt @@ -1,7 +1,5 @@ fun foo() = -// EXIST: break -// EXIST: continue // EXIST: do // EXIST: false // EXIST: for @@ -15,4 +13,4 @@ fun foo() = // EXIST: try // EXIST: when // EXIST: while -// NUMBER: 15 +// NUMBER: 13 diff --git a/idea/testData/completion/keywords/InGetterExpressionBody.kt b/idea/testData/completion/keywords/InGetterExpressionBody.kt index fec7ce70855..c320d43f385 100644 --- a/idea/testData/completion/keywords/InGetterExpressionBody.kt +++ b/idea/testData/completion/keywords/InGetterExpressionBody.kt @@ -1,8 +1,6 @@ val prop: Int get() = -// EXIST: break -// EXIST: continue // EXIST: do // EXIST: false // EXIST: for @@ -16,4 +14,4 @@ val prop: Int // EXIST: try // EXIST: when // EXIST: while -// NUMBER: 15 +// NUMBER: 13 diff --git a/idea/testData/completion/keywords/InParameterDefaultValue.kt b/idea/testData/completion/keywords/InParameterDefaultValue.kt index a2e2b9b1f9e..ca22a6d05b3 100644 --- a/idea/testData/completion/keywords/InParameterDefaultValue.kt +++ b/idea/testData/completion/keywords/InParameterDefaultValue.kt @@ -1,7 +1,5 @@ fun foo(p: Int = ) -// EXIST: break -// EXIST: continue // EXIST: do // EXIST: false // EXIST: for @@ -16,4 +14,4 @@ fun foo(p: Int = ) // EXIST: try // EXIST: when // EXIST: while -// NUMBER: 16 +// NUMBER: 14 diff --git a/idea/testData/completion/keywords/InPropertyInitializer.kt b/idea/testData/completion/keywords/InPropertyInitializer.kt index c5975fa6e3f..6a687339d54 100644 --- a/idea/testData/completion/keywords/InPropertyInitializer.kt +++ b/idea/testData/completion/keywords/InPropertyInitializer.kt @@ -1,7 +1,5 @@ var a : Int = -// EXIST: break -// EXIST: continue // EXIST: do // EXIST: false // EXIST: for @@ -15,4 +13,4 @@ var a : Int = // EXIST: try // EXIST: when // EXIST: while -// NUMBER: 15 +// NUMBER: 13 diff --git a/idea/testData/completion/keywords/NoBreak1.kt b/idea/testData/completion/keywords/NoBreak1.kt new file mode 100644 index 00000000000..304a1f08870 --- /dev/null +++ b/idea/testData/completion/keywords/NoBreak1.kt @@ -0,0 +1,14 @@ +fun foo() { + @myFor + for (i in 1..10) { + while (x()) { + fun localFun(a: Int) { + if (a > 0) { + br + } + } + } + } +} + +// NUMBER: 0 diff --git a/idea/testData/completion/keywords/NoBreak2.kt b/idea/testData/completion/keywords/NoBreak2.kt new file mode 100644 index 00000000000..17132ab5828 --- /dev/null +++ b/idea/testData/completion/keywords/NoBreak2.kt @@ -0,0 +1,12 @@ +fun foo() { + @myFor + for (i in 1..10) { + while (x()) { + "abc".filter { + br + } + } + } +} + +// NUMBER: 0 diff --git a/idea/testData/completion/keywords/NoContinue.kt b/idea/testData/completion/keywords/NoContinue.kt new file mode 100644 index 00000000000..632578c2e97 --- /dev/null +++ b/idea/testData/completion/keywords/NoContinue.kt @@ -0,0 +1,14 @@ +fun foo() { + @myFor + for (i in 1..10) { + while (x()) { + fun localFun(a: Int) { + if (a > 0) { + con + } + } + } + } +} + +// NUMBER: 0 diff --git a/idea/testData/completion/weighers/basic/PropertiesBeforeKeywords.kt b/idea/testData/completion/weighers/basic/PropertiesBeforeKeywords.kt index 3e11bb3db2d..46c9616b861 100644 --- a/idea/testData/completion/weighers/basic/PropertiesBeforeKeywords.kt +++ b/idea/testData/completion/weighers/basic/PropertiesBeforeKeywords.kt @@ -8,8 +8,10 @@ class Test(val br2 = 12) { fun brf() = 112 fun test(br4: Int) { - val br5 = 14 - br + while (true) { + val br5 = 14 + br + } } } diff --git a/idea/tests/org/jetbrains/jet/completion/KeywordCompletionTestGenerated.java b/idea/tests/org/jetbrains/jet/completion/KeywordCompletionTestGenerated.java index 3a70337b2ae..090fceae078 100644 --- a/idea/tests/org/jetbrains/jet/completion/KeywordCompletionTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/completion/KeywordCompletionTestGenerated.java @@ -19,7 +19,6 @@ package org.jetbrains.jet.completion; import com.intellij.testFramework.TestDataPath; import org.jetbrains.jet.JUnit3RunnerWithInners; import org.jetbrains.jet.JetTestUtils; -import org.jetbrains.jet.test.InnerTestClasses; import org.jetbrains.jet.test.TestMetadata; import org.junit.runner.RunWith; @@ -78,12 +77,30 @@ public class KeywordCompletionTestGenerated extends AbstractKeywordCompletionTes JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/completion/keywords"), Pattern.compile("^(.+)\\.kt$"), false); } + @TestMetadata("BreakContinue.kt") + public void testBreakContinue() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/keywords/BreakContinue.kt"); + doTest(fileName); + } + + @TestMetadata("BreakWithLabel.kt") + public void testBreakWithLabel() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/keywords/BreakWithLabel.kt"); + doTest(fileName); + } + @TestMetadata("CommaExpected.kt") public void testCommaExpected() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/keywords/CommaExpected.kt"); doTest(fileName); } + @TestMetadata("ContinueWithLabel.kt") + public void testContinueWithLabel() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/keywords/ContinueWithLabel.kt"); + doTest(fileName); + } + @TestMetadata("GlobalPropertyAccessors.kt") public void testGlobalPropertyAccessors() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/keywords/GlobalPropertyAccessors.kt"); @@ -240,12 +257,30 @@ public class KeywordCompletionTestGenerated extends AbstractKeywordCompletionTes doTest(fileName); } + @TestMetadata("NoBreak1.kt") + public void testNoBreak1() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/keywords/NoBreak1.kt"); + doTest(fileName); + } + + @TestMetadata("NoBreak2.kt") + public void testNoBreak2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/keywords/NoBreak2.kt"); + doTest(fileName); + } + @TestMetadata("NoCompletionForCapitalPrefix.kt") public void testNoCompletionForCapitalPrefix() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/keywords/NoCompletionForCapitalPrefix.kt"); doTest(fileName); } + @TestMetadata("NoContinue.kt") + public void testNoContinue() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/keywords/NoContinue.kt"); + doTest(fileName); + } + @TestMetadata("NoFinalInParameterList.kt") public void testNoFinalInParameterList() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/keywords/NoFinalInParameterList.kt");