KT-5874 Support code completion of label names after "continue@" and "break@"
#KT-5874 Fixed
This commit is contained in:
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<LookupElement> {
|
||||
val result = ArrayList<LookupElement>()
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
fun t() {
|
||||
brea<caret>
|
||||
while (true) {
|
||||
brea<caret>
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
fun t() {
|
||||
break<caret>
|
||||
while (true) {
|
||||
break<caret>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
fun foo() {
|
||||
@myFor
|
||||
for (i in 1..10) {
|
||||
@myWhile
|
||||
while (x()) {
|
||||
@myDo
|
||||
do {
|
||||
<caret>
|
||||
} 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" }
|
||||
@@ -0,0 +1,17 @@
|
||||
fun foo() {
|
||||
@myFor
|
||||
for (i in 1..10) {
|
||||
@myWhile
|
||||
while (x()) {
|
||||
@myDo
|
||||
do {
|
||||
break@<caret>
|
||||
} 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
|
||||
@@ -0,0 +1,17 @@
|
||||
fun foo() {
|
||||
@myFor
|
||||
for (i in 1..10) {
|
||||
@myWhile
|
||||
while (x()) {
|
||||
@myDo
|
||||
do {
|
||||
continue@<caret>
|
||||
} 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
|
||||
@@ -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
|
||||
|
||||
@@ -2,9 +2,7 @@ fun foo() {
|
||||
<caret>
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
fun foo() = <caret>
|
||||
|
||||
// EXIST: break
|
||||
// EXIST: continue
|
||||
// EXIST: do
|
||||
// EXIST: false
|
||||
// EXIST: for
|
||||
@@ -15,4 +13,4 @@ fun foo() = <caret>
|
||||
// EXIST: try
|
||||
// EXIST: when
|
||||
// EXIST: while
|
||||
// NUMBER: 15
|
||||
// NUMBER: 13
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
val prop: Int
|
||||
get() = <caret>
|
||||
|
||||
// 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
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
fun foo(p: Int = <caret>)
|
||||
|
||||
// EXIST: break
|
||||
// EXIST: continue
|
||||
// EXIST: do
|
||||
// EXIST: false
|
||||
// EXIST: for
|
||||
@@ -16,4 +14,4 @@ fun foo(p: Int = <caret>)
|
||||
// EXIST: try
|
||||
// EXIST: when
|
||||
// EXIST: while
|
||||
// NUMBER: 16
|
||||
// NUMBER: 14
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
var a : Int = <caret>
|
||||
|
||||
// EXIST: break
|
||||
// EXIST: continue
|
||||
// EXIST: do
|
||||
// EXIST: false
|
||||
// EXIST: for
|
||||
@@ -15,4 +13,4 @@ var a : Int = <caret>
|
||||
// EXIST: try
|
||||
// EXIST: when
|
||||
// EXIST: while
|
||||
// NUMBER: 15
|
||||
// NUMBER: 13
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
fun foo() {
|
||||
@myFor
|
||||
for (i in 1..10) {
|
||||
while (x()) {
|
||||
fun localFun(a: Int) {
|
||||
if (a > 0) {
|
||||
br<caret>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NUMBER: 0
|
||||
@@ -0,0 +1,12 @@
|
||||
fun foo() {
|
||||
@myFor
|
||||
for (i in 1..10) {
|
||||
while (x()) {
|
||||
"abc".filter {
|
||||
br<caret>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NUMBER: 0
|
||||
@@ -0,0 +1,14 @@
|
||||
fun foo() {
|
||||
@myFor
|
||||
for (i in 1..10) {
|
||||
while (x()) {
|
||||
fun localFun(a: Int) {
|
||||
if (a > 0) {
|
||||
con<caret>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NUMBER: 0
|
||||
@@ -8,8 +8,10 @@ class Test(val br2 = 12) {
|
||||
fun brf() = 112
|
||||
|
||||
fun test(br4: Int) {
|
||||
val br5 = 14
|
||||
br<caret>
|
||||
while (true) {
|
||||
val br5 = 14
|
||||
br<caret>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user