From be7158eeb2e95249201be8573112b601d224ecb8 Mon Sep 17 00:00:00 2001 From: Simon Ogorodnik Date: Mon, 6 Feb 2017 19:17:42 +0300 Subject: [PATCH] KT-16110 Missing suspend keyword completion inside generic arguments #KT-16110 fixed --- .../idea/completion/KeywordCompletion.kt | 55 +++++++++++++------ .../testData/keywords/AfterClassProperty.kt | 4 +- .../testData/keywords/AfterClasses.kt | 2 +- .../keywords/AfterClasses_LangLevel10.kt | 2 +- .../testData/keywords/AfterFuns.kt | 2 +- .../keywords/GlobalPropertyAccessors.kt | 2 +- .../keywords/InAnnotationClassScope.kt | 2 +- .../testData/keywords/InClassBeforeFun.kt | 2 +- .../testData/keywords/InClassScope.kt | 2 +- .../testData/keywords/InEnumScope2.kt | 2 +- .../testData/keywords/InInterfaceScope.kt | 2 +- .../testData/keywords/InObjectScope.kt | 2 +- .../keywords/InTopScopeAfterPackage.kt | 2 +- .../testData/keywords/PropertyAccessors.kt | 2 +- .../testData/keywords/PropertyAccessors2.kt | 2 +- .../testData/keywords/PropertySetter.kt | 2 +- .../keywords/SuspendInsideTypeArguments.kt | 35 ++++++++++++ .../keywords/SuspendInsideTypeArguments1.kt | 32 +++++++++++ .../testData/keywords/TopScope.kt | 2 +- .../test/KeywordCompletionTestGenerated.java | 12 ++++ 20 files changed, 135 insertions(+), 33 deletions(-) create mode 100644 idea/idea-completion/testData/keywords/SuspendInsideTypeArguments.kt create mode 100644 idea/idea-completion/testData/keywords/SuspendInsideTypeArguments1.kt diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KeywordCompletion.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KeywordCompletion.kt index 365aef67f5f..539cc7642a2 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KeywordCompletion.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KeywordCompletion.kt @@ -57,7 +57,8 @@ object KeywordCompletion { private val COMPOUND_KEYWORDS = mapOf( COMPANION_KEYWORD to OBJECT_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( @@ -228,24 +229,25 @@ object KeywordCompletion { return buildFilterWithContext("val v = ", default!!, position) } } - } - if (parent is KtDeclaration) { - val scope = parent.parent - when (scope) { - is KtClassOrObject -> { - if (parent is KtPrimaryConstructor) { - return buildFilterWithReducedContext("class X ", parent, position) - } - else { - return buildFilterWithReducedContext("class X { ", parent, position) + is KtDeclaration -> { + val scope = parent.parent + when (scope) { + is KtClassOrObject -> { + if (parent is KtPrimaryConstructor) { + return buildFilterWithReducedContext("class X ", parent, position) + } + else { + return buildFilterWithReducedContext("class X { ", parent, position) + } } + + is KtFile -> return buildFilterWithReducedContext("", parent, position) } - - is KtFile -> return buildFilterWithReducedContext("", parent, position) } } + prevParent = parent parent = parent.parent } @@ -253,6 +255,18 @@ object KeywordCompletion { return buildFilterWithReducedContext("", null, position) } + fun computeKeywordApplications(prefixText: String, keyword: KtKeywordToken): Sequence { + 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, contextElement: PsiElement, position: PsiElement): (KtKeywordToken) -> Boolean { @@ -270,11 +284,15 @@ object KeywordCompletion { } + private fun buildFilesWithKeywordApplication(keywordTokenType: KtKeywordToken, prefixText: String, psiFactory: KtPsiFactory): Sequence { + return computeKeywordApplications(prefixText, keywordTokenType) + .map { application -> psiFactory.createFile(prefixText + application) } + } + + private fun buildFilterByText(prefixText: String, position: PsiElement): (KtKeywordToken) -> Boolean { val psiFactory = KtPsiFactory(position.project) - return fun (keywordTokenType): Boolean { - val postfix = if (prefixText.endsWith("@")) ":X Y.Z" else " X" - val file = psiFactory.createFile(prefixText + keywordTokenType.value + postfix) + fun isKeywordCorrectlyApplied(keywordTokenType: KtKeywordToken, file: KtFile): Boolean { val elementAt = file.findElementAt(prefixText.length)!! 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 { diff --git a/idea/idea-completion/testData/keywords/AfterClassProperty.kt b/idea/idea-completion/testData/keywords/AfterClassProperty.kt index 960d53e7aa0..e6187c6f778 100644 --- a/idea/idea-completion/testData/keywords/AfterClassProperty.kt +++ b/idea/idea-completion/testData/keywords/AfterClassProperty.kt @@ -1,6 +1,6 @@ class MouseMovedEventArgs { - public val X : int = 0 + public val X : Int = 0 } @@ -32,7 +32,7 @@ class MouseMovedEventArgs // EXIST: companion object // EXIST: operator // EXIST: infix -// EXIST: sealed +// EXIST: sealed class // EXIST: lateinit // EXIST: data // EXIST: inline diff --git a/idea/idea-completion/testData/keywords/AfterClasses.kt b/idea/idea-completion/testData/keywords/AfterClasses.kt index eb12039fe67..1d3bef6f5c3 100644 --- a/idea/idea-completion/testData/keywords/AfterClasses.kt +++ b/idea/idea-completion/testData/keywords/AfterClasses.kt @@ -27,7 +27,7 @@ class B { // EXIST: var // EXIST: operator // EXIST: infix -// EXIST: sealed +// EXIST: sealed class // EXIST: data // EXIST: inline // EXIST: tailrec diff --git a/idea/idea-completion/testData/keywords/AfterClasses_LangLevel10.kt b/idea/idea-completion/testData/keywords/AfterClasses_LangLevel10.kt index 6b906e958da..14fcbd9e20a 100644 --- a/idea/idea-completion/testData/keywords/AfterClasses_LangLevel10.kt +++ b/idea/idea-completion/testData/keywords/AfterClasses_LangLevel10.kt @@ -27,7 +27,7 @@ class B { // EXIST: var // EXIST: operator // EXIST: infix -// EXIST: sealed +// EXIST: sealed class // EXIST: data // EXIST: inline // EXIST: tailrec diff --git a/idea/idea-completion/testData/keywords/AfterFuns.kt b/idea/idea-completion/testData/keywords/AfterFuns.kt index 3e40ae69b76..53cc4138b0a 100644 --- a/idea/idea-completion/testData/keywords/AfterFuns.kt +++ b/idea/idea-completion/testData/keywords/AfterFuns.kt @@ -31,7 +31,7 @@ class A { // EXIST: companion object // EXIST: operator // EXIST: infix -// EXIST: sealed +// EXIST: sealed class // EXIST: lateinit // EXIST: data // EXIST: inline diff --git a/idea/idea-completion/testData/keywords/GlobalPropertyAccessors.kt b/idea/idea-completion/testData/keywords/GlobalPropertyAccessors.kt index 06cb86035d9..fc693aadd71 100644 --- a/idea/idea-completion/testData/keywords/GlobalPropertyAccessors.kt +++ b/idea/idea-completion/testData/keywords/GlobalPropertyAccessors.kt @@ -31,7 +31,7 @@ var a : Int // EXIST: var // EXIST: operator // EXIST: infix -// EXIST: sealed +// EXIST: sealed class // EXIST: data // EXIST: inline // EXIST: tailrec diff --git a/idea/idea-completion/testData/keywords/InAnnotationClassScope.kt b/idea/idea-completion/testData/keywords/InAnnotationClassScope.kt index 3107c56e48b..69a59dcfbb5 100644 --- a/idea/idea-completion/testData/keywords/InAnnotationClassScope.kt +++ b/idea/idea-completion/testData/keywords/InAnnotationClassScope.kt @@ -17,7 +17,7 @@ annotation class Test { // EXIST: init // EXIST: operator // EXIST: infix -// EXIST: sealed +// EXIST: sealed class // EXIST: lateinit // EXIST: data // EXIST: inline diff --git a/idea/idea-completion/testData/keywords/InClassBeforeFun.kt b/idea/idea-completion/testData/keywords/InClassBeforeFun.kt index 2d96475ec83..00f7bf3233e 100644 --- a/idea/idea-completion/testData/keywords/InClassBeforeFun.kt +++ b/idea/idea-completion/testData/keywords/InClassBeforeFun.kt @@ -29,7 +29,7 @@ public class Test { // EXIST: companion object // EXIST: operator // EXIST: infix -// EXIST: sealed +// EXIST: sealed class // EXIST: lateinit // EXIST: data // EXIST: inline diff --git a/idea/idea-completion/testData/keywords/InClassScope.kt b/idea/idea-completion/testData/keywords/InClassScope.kt index 42718e17b6b..56e6e5c7002 100644 --- a/idea/idea-completion/testData/keywords/InClassScope.kt +++ b/idea/idea-completion/testData/keywords/InClassScope.kt @@ -23,7 +23,7 @@ class TestClass { // EXIST: companion object // EXIST: operator // EXIST: infix -// EXIST: sealed +// EXIST: sealed class // EXIST: lateinit // EXIST: data // EXIST: inline diff --git a/idea/idea-completion/testData/keywords/InEnumScope2.kt b/idea/idea-completion/testData/keywords/InEnumScope2.kt index e63f517f2df..91f644c66e2 100644 --- a/idea/idea-completion/testData/keywords/InEnumScope2.kt +++ b/idea/idea-completion/testData/keywords/InEnumScope2.kt @@ -17,7 +17,7 @@ enum class Test { // EXIST: companion object // EXIST: operator // EXIST: infix -// EXIST: sealed +// EXIST: sealed class // EXIST: lateinit // EXIST: data // EXIST: inline diff --git a/idea/idea-completion/testData/keywords/InInterfaceScope.kt b/idea/idea-completion/testData/keywords/InInterfaceScope.kt index 011a6e3d070..459245ef72c 100644 --- a/idea/idea-completion/testData/keywords/InInterfaceScope.kt +++ b/idea/idea-completion/testData/keywords/InInterfaceScope.kt @@ -19,7 +19,7 @@ interface Test { // EXIST: companion object // EXIST: operator // EXIST: infix -// EXIST: sealed +// EXIST: sealed class // EXIST: lateinit // EXIST: data // EXIST: inline diff --git a/idea/idea-completion/testData/keywords/InObjectScope.kt b/idea/idea-completion/testData/keywords/InObjectScope.kt index b3fd60d167f..9d5da45884f 100644 --- a/idea/idea-completion/testData/keywords/InObjectScope.kt +++ b/idea/idea-completion/testData/keywords/InObjectScope.kt @@ -20,7 +20,7 @@ object Test { // EXIST: init // EXIST: operator // EXIST: infix -// EXIST: sealed +// EXIST: sealed class // EXIST: lateinit // EXIST: data // EXIST: inline diff --git a/idea/idea-completion/testData/keywords/InTopScopeAfterPackage.kt b/idea/idea-completion/testData/keywords/InTopScopeAfterPackage.kt index dea8c50daf6..d77855dd56c 100644 --- a/idea/idea-completion/testData/keywords/InTopScopeAfterPackage.kt +++ b/idea/idea-completion/testData/keywords/InTopScopeAfterPackage.kt @@ -18,7 +18,7 @@ package Test // EXIST: var // EXIST: operator // EXIST: infix -// EXIST: sealed +// EXIST: sealed class // EXIST: data // EXIST: inline // EXIST: tailrec diff --git a/idea/idea-completion/testData/keywords/PropertyAccessors.kt b/idea/idea-completion/testData/keywords/PropertyAccessors.kt index 83144925e43..0a62241a005 100644 --- a/idea/idea-completion/testData/keywords/PropertyAccessors.kt +++ b/idea/idea-completion/testData/keywords/PropertyAccessors.kt @@ -31,7 +31,7 @@ class Some { // EXIST: companion object // EXIST: operator // EXIST: infix -// EXIST: sealed +// EXIST: sealed class // EXIST: lateinit // EXIST: data // EXIST: inline diff --git a/idea/idea-completion/testData/keywords/PropertyAccessors2.kt b/idea/idea-completion/testData/keywords/PropertyAccessors2.kt index 74bf2304b4b..2e116ddf721 100644 --- a/idea/idea-completion/testData/keywords/PropertyAccessors2.kt +++ b/idea/idea-completion/testData/keywords/PropertyAccessors2.kt @@ -31,7 +31,7 @@ class Some { // EXIST: companion object // EXIST: operator // EXIST: infix -// EXIST: sealed +// EXIST: sealed class // EXIST: lateinit // EXIST: data // EXIST: inline diff --git a/idea/idea-completion/testData/keywords/PropertySetter.kt b/idea/idea-completion/testData/keywords/PropertySetter.kt index 9f6a61afa35..a8070bbc5a2 100644 --- a/idea/idea-completion/testData/keywords/PropertySetter.kt +++ b/idea/idea-completion/testData/keywords/PropertySetter.kt @@ -29,7 +29,7 @@ class Some { // EXIST: companion object // EXIST: operator // EXIST: infix -// EXIST: sealed +// EXIST: sealed class // EXIST: lateinit // EXIST: data // EXIST: inline diff --git a/idea/idea-completion/testData/keywords/SuspendInsideTypeArguments.kt b/idea/idea-completion/testData/keywords/SuspendInsideTypeArguments.kt new file mode 100644 index 00000000000..498717586e8 --- /dev/null +++ b/idea/idea-completion/testData/keywords/SuspendInsideTypeArguments.kt @@ -0,0 +1,35 @@ +class Su() { + fun x() { + mutableListOf<>() + } +} + + +// 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 + + + diff --git a/idea/idea-completion/testData/keywords/SuspendInsideTypeArguments1.kt b/idea/idea-completion/testData/keywords/SuspendInsideTypeArguments1.kt new file mode 100644 index 00000000000..26001b1e917 --- /dev/null +++ b/idea/idea-completion/testData/keywords/SuspendInsideTypeArguments1.kt @@ -0,0 +1,32 @@ +class Su() { + fun x() { + mutableListOf, 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 \ No newline at end of file diff --git a/idea/idea-completion/testData/keywords/TopScope.kt b/idea/idea-completion/testData/keywords/TopScope.kt index 1793dbb9349..fd5bef074aa 100644 --- a/idea/idea-completion/testData/keywords/TopScope.kt +++ b/idea/idea-completion/testData/keywords/TopScope.kt @@ -17,7 +17,7 @@ // EXIST: var // EXIST: operator // EXIST: infix -// EXIST: sealed +// EXIST: sealed class // EXIST: data // EXIST: inline // EXIST: tailrec diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/KeywordCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/KeywordCompletionTestGenerated.java index 991194e6128..81f488c9f8f 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/KeywordCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/KeywordCompletionTestGenerated.java @@ -546,6 +546,18 @@ public class KeywordCompletionTestGenerated extends AbstractKeywordCompletionTes 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") public void testThis() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/This.kt");