KT-16110 Missing suspend keyword completion inside generic arguments
#KT-16110 fixed
This commit is contained in:
+39
-16
@@ -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
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
|
|||||||
+12
@@ -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");
|
||||||
|
|||||||
Reference in New Issue
Block a user