KT-16110 Missing suspend keyword completion inside generic arguments

#KT-16110 fixed
This commit is contained in:
Simon Ogorodnik
2017-02-06 19:17:42 +03:00
parent 5895c211a1
commit be7158eeb2
20 changed files with 135 additions and 33 deletions
@@ -57,7 +57,8 @@ object KeywordCompletion {
private val COMPOUND_KEYWORDS = mapOf<KtKeywordToken, KtKeywordToken>( private val COMPOUND_KEYWORDS = mapOf<KtKeywordToken, KtKeywordToken>(
COMPANION_KEYWORD to OBJECT_KEYWORD, COMPANION_KEYWORD to OBJECT_KEYWORD,
ENUM_KEYWORD to CLASS_KEYWORD, ENUM_KEYWORD to CLASS_KEYWORD,
ANNOTATION_KEYWORD to CLASS_KEYWORD ANNOTATION_KEYWORD to CLASS_KEYWORD,
SEALED_KEYWORD to CLASS_KEYWORD
) )
private val KEYWORD_CONSTRUCTS = mapOf<KtKeywordToken, String>( private val KEYWORD_CONSTRUCTS = mapOf<KtKeywordToken, String>(
@@ -228,24 +229,25 @@ object KeywordCompletion {
return buildFilterWithContext("val v = ", default!!, position) return buildFilterWithContext("val v = ", default!!, position)
} }
} }
}
if (parent is KtDeclaration) { is KtDeclaration -> {
val scope = parent.parent val scope = parent.parent
when (scope) { when (scope) {
is KtClassOrObject -> { is KtClassOrObject -> {
if (parent is KtPrimaryConstructor) { if (parent is KtPrimaryConstructor) {
return buildFilterWithReducedContext("class X ", parent, position) return buildFilterWithReducedContext("class X ", parent, position)
} }
else { else {
return buildFilterWithReducedContext("class X { ", parent, position) return buildFilterWithReducedContext("class X { ", parent, position)
}
} }
is KtFile -> return buildFilterWithReducedContext("", parent, position)
} }
is KtFile -> return buildFilterWithReducedContext("", parent, position)
} }
} }
prevParent = parent prevParent = parent
parent = parent.parent parent = parent.parent
} }
@@ -253,6 +255,18 @@ object KeywordCompletion {
return buildFilterWithReducedContext("", null, position) return buildFilterWithReducedContext("", null, position)
} }
fun computeKeywordApplications(prefixText: String, keyword: KtKeywordToken): Sequence<String> {
return when (keyword) {
SUSPEND_KEYWORD -> sequenceOf("suspend () -> Unit>", "suspend X")
else -> {
if (prefixText.endsWith("@"))
sequenceOf(keyword.value + ":X Y.Z")
else
sequenceOf(keyword.value + " X")
}
}
}
private fun buildFilterWithContext(prefixText: String, private fun buildFilterWithContext(prefixText: String,
contextElement: PsiElement, contextElement: PsiElement,
position: PsiElement): (KtKeywordToken) -> Boolean { position: PsiElement): (KtKeywordToken) -> Boolean {
@@ -270,11 +284,15 @@ object KeywordCompletion {
} }
private fun buildFilesWithKeywordApplication(keywordTokenType: KtKeywordToken, prefixText: String, psiFactory: KtPsiFactory): Sequence<KtFile> {
return computeKeywordApplications(prefixText, keywordTokenType)
.map { application -> psiFactory.createFile(prefixText + application) }
}
private fun buildFilterByText(prefixText: String, position: PsiElement): (KtKeywordToken) -> Boolean { private fun buildFilterByText(prefixText: String, position: PsiElement): (KtKeywordToken) -> Boolean {
val psiFactory = KtPsiFactory(position.project) val psiFactory = KtPsiFactory(position.project)
return fun (keywordTokenType): Boolean { fun isKeywordCorrectlyApplied(keywordTokenType: KtKeywordToken, file: KtFile): Boolean {
val postfix = if (prefixText.endsWith("@")) ":X Y.Z" else " X"
val file = psiFactory.createFile(prefixText + keywordTokenType.value + postfix)
val elementAt = file.findElementAt(prefixText.length)!! val elementAt = file.findElementAt(prefixText.length)!!
when { when {
@@ -341,6 +359,11 @@ object KeywordCompletion {
} }
} }
} }
return fun (keywordTokenType): Boolean {
val files = buildFilesWithKeywordApplication(keywordTokenType, prefixText, psiFactory)
return files.any { file -> isKeywordCorrectlyApplied(keywordTokenType, file); }
}
} }
private fun isErrorElementBefore(token: PsiElement): Boolean { private fun isErrorElementBefore(token: PsiElement): Boolean {
@@ -1,6 +1,6 @@
class MouseMovedEventArgs class MouseMovedEventArgs
{ {
public val X : int = 0 public val X : Int = 0
<caret> <caret>
} }
@@ -32,7 +32,7 @@ class MouseMovedEventArgs
// EXIST: companion object // EXIST: companion object
// EXIST: operator // EXIST: operator
// EXIST: infix // EXIST: infix
// EXIST: sealed // EXIST: sealed class
// EXIST: lateinit // EXIST: lateinit
// EXIST: data // EXIST: data
// EXIST: inline // EXIST: inline
+1 -1
View File
@@ -27,7 +27,7 @@ class B {
// EXIST: var // EXIST: var
// EXIST: operator // EXIST: operator
// EXIST: infix // EXIST: infix
// EXIST: sealed // EXIST: sealed class
// EXIST: data // EXIST: data
// EXIST: inline // EXIST: inline
// EXIST: tailrec // EXIST: tailrec
@@ -27,7 +27,7 @@ class B {
// EXIST: var // EXIST: var
// EXIST: operator // EXIST: operator
// EXIST: infix // EXIST: infix
// EXIST: sealed // EXIST: sealed class
// EXIST: data // EXIST: data
// EXIST: inline // EXIST: inline
// EXIST: tailrec // EXIST: tailrec
+1 -1
View File
@@ -31,7 +31,7 @@ class A {
// EXIST: companion object // EXIST: companion object
// EXIST: operator // EXIST: operator
// EXIST: infix // EXIST: infix
// EXIST: sealed // EXIST: sealed class
// EXIST: lateinit // EXIST: lateinit
// EXIST: data // EXIST: data
// EXIST: inline // EXIST: inline
@@ -31,7 +31,7 @@ var a : Int
// EXIST: var // EXIST: var
// EXIST: operator // EXIST: operator
// EXIST: infix // EXIST: infix
// EXIST: sealed // EXIST: sealed class
// EXIST: data // EXIST: data
// EXIST: inline // EXIST: inline
// EXIST: tailrec // EXIST: tailrec
@@ -17,7 +17,7 @@ annotation class Test {
// EXIST: init // EXIST: init
// EXIST: operator // EXIST: operator
// EXIST: infix // EXIST: infix
// EXIST: sealed // EXIST: sealed class
// EXIST: lateinit // EXIST: lateinit
// EXIST: data // EXIST: data
// EXIST: inline // EXIST: inline
+1 -1
View File
@@ -29,7 +29,7 @@ public class Test {
// EXIST: companion object // EXIST: companion object
// EXIST: operator // EXIST: operator
// EXIST: infix // EXIST: infix
// EXIST: sealed // EXIST: sealed class
// EXIST: lateinit // EXIST: lateinit
// EXIST: data // EXIST: data
// EXIST: inline // EXIST: inline
+1 -1
View File
@@ -23,7 +23,7 @@ class TestClass {
// EXIST: companion object // EXIST: companion object
// EXIST: operator // EXIST: operator
// EXIST: infix // EXIST: infix
// EXIST: sealed // EXIST: sealed class
// EXIST: lateinit // EXIST: lateinit
// EXIST: data // EXIST: data
// EXIST: inline // EXIST: inline
+1 -1
View File
@@ -17,7 +17,7 @@ enum class Test {
// EXIST: companion object // EXIST: companion object
// EXIST: operator // EXIST: operator
// EXIST: infix // EXIST: infix
// EXIST: sealed // EXIST: sealed class
// EXIST: lateinit // EXIST: lateinit
// EXIST: data // EXIST: data
// EXIST: inline // EXIST: inline
+1 -1
View File
@@ -19,7 +19,7 @@ interface Test {
// EXIST: companion object // EXIST: companion object
// EXIST: operator // EXIST: operator
// EXIST: infix // EXIST: infix
// EXIST: sealed // EXIST: sealed class
// EXIST: lateinit // EXIST: lateinit
// EXIST: data // EXIST: data
// EXIST: inline // EXIST: inline
+1 -1
View File
@@ -20,7 +20,7 @@ object Test {
// EXIST: init // EXIST: init
// EXIST: operator // EXIST: operator
// EXIST: infix // EXIST: infix
// EXIST: sealed // EXIST: sealed class
// EXIST: lateinit // EXIST: lateinit
// EXIST: data // EXIST: data
// EXIST: inline // EXIST: inline
@@ -18,7 +18,7 @@ package Test
// EXIST: var // EXIST: var
// EXIST: operator // EXIST: operator
// EXIST: infix // EXIST: infix
// EXIST: sealed // EXIST: sealed class
// EXIST: data // EXIST: data
// EXIST: inline // EXIST: inline
// EXIST: tailrec // EXIST: tailrec
@@ -31,7 +31,7 @@ class Some {
// EXIST: companion object // EXIST: companion object
// EXIST: operator // EXIST: operator
// EXIST: infix // EXIST: infix
// EXIST: sealed // EXIST: sealed class
// EXIST: lateinit // EXIST: lateinit
// EXIST: data // EXIST: data
// EXIST: inline // EXIST: inline
@@ -31,7 +31,7 @@ class Some {
// EXIST: companion object // EXIST: companion object
// EXIST: operator // EXIST: operator
// EXIST: infix // EXIST: infix
// EXIST: sealed // EXIST: sealed class
// EXIST: lateinit // EXIST: lateinit
// EXIST: data // EXIST: data
// EXIST: inline // EXIST: inline
+1 -1
View File
@@ -29,7 +29,7 @@ class Some {
// EXIST: companion object // EXIST: companion object
// EXIST: operator // EXIST: operator
// EXIST: infix // EXIST: infix
// EXIST: sealed // EXIST: sealed class
// EXIST: lateinit // EXIST: lateinit
// EXIST: data // EXIST: data
// EXIST: inline // EXIST: inline
@@ -0,0 +1,35 @@
class Su() {
fun x() {
mutableListOf<<caret>>()
}
}
// EXIST: suspend
/* TODO: items below are not valid here */
// EXIST: class
// EXIST: do
// EXIST: false
// EXIST: for
// EXIST: fun
// EXIST: if
// EXIST: interface
// EXIST: null
// EXIST: object
// EXIST: return
// EXIST: super
// EXIST: this
// EXIST: throw
// EXIST: true
// EXIST: try
// EXIST: typealias
// EXIST: val
// EXIST: var
// EXIST: when
// EXIST: while
// NOTHING_ELSE
@@ -0,0 +1,32 @@
class Su() {
fun x() {
mutableListOf<Pair<<caret>, String>>()
}
}
// EXIST: suspend
/* TODO: items below are not valid here */
// EXIST: class
// EXIST: do
// EXIST: false
// EXIST: for
// EXIST: fun
// EXIST: if
// EXIST: interface
// EXIST: null
// EXIST: object
// EXIST: return
// EXIST: super
// EXIST: this
// EXIST: throw
// EXIST: true
// EXIST: try
// EXIST: typealias
// EXIST: val
// EXIST: var
// EXIST: when
// EXIST: while
// NOTHING_ELSE
+1 -1
View File
@@ -17,7 +17,7 @@
// EXIST: var // EXIST: var
// EXIST: operator // EXIST: operator
// EXIST: infix // EXIST: infix
// EXIST: sealed // EXIST: sealed class
// EXIST: data // EXIST: data
// EXIST: inline // EXIST: inline
// EXIST: tailrec // EXIST: tailrec
@@ -546,6 +546,18 @@ public class KeywordCompletionTestGenerated extends AbstractKeywordCompletionTes
doTest(fileName); doTest(fileName);
} }
@TestMetadata("SuspendInsideTypeArguments.kt")
public void testSuspendInsideTypeArguments() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/SuspendInsideTypeArguments.kt");
doTest(fileName);
}
@TestMetadata("SuspendInsideTypeArguments1.kt")
public void testSuspendInsideTypeArguments1() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/SuspendInsideTypeArguments1.kt");
doTest(fileName);
}
@TestMetadata("This.kt") @TestMetadata("This.kt")
public void testThis() throws Exception { public void testThis() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/This.kt"); String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/This.kt");