KT-5874 Support code completion of label names after "continue@" and "break@"

#KT-5874 Fixed
This commit is contained in:
Valentin Kipyatkov
2014-12-26 20:25:00 +03:00
parent 4800a02e69
commit 51678d0a45
18 changed files with 178 additions and 24 deletions
@@ -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");