From f67bd8c13f85c2494b54122ce439bfba66632256 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Tue, 13 Oct 2015 18:15:13 +0300 Subject: [PATCH] Even more precise keyword completion for modifiers --- .../kotlin/resolve/ModifiersChecker.kt | 4 +- .../idea/completion/KeywordCompletion.kt | 40 ++++++++++++++++--- .../testData/keywords/AfterClasses.kt | 5 --- .../keywords/GlobalPropertyAccessors.kt | 3 -- .../keywords/InAnnotationClassScope.kt | 28 +++++++++++++ .../testData/keywords/InEnumScope1.kt | 5 +++ .../testData/keywords/InEnumScope2.kt | 39 ++++++++++++++++++ .../testData/keywords/InInterfaceScope.kt | 30 ++++++++++++++ .../testData/keywords/InObjectScope.kt | 31 ++++++++++++++ .../keywords/InTopScopeAfterPackage.kt | 3 -- .../testData/keywords/PrefixMatcher.kt | 1 - .../testData/keywords/TopScope.kt | 3 -- .../test/KeywordCompletionTestGenerated.java | 30 ++++++++++++++ 13 files changed, 200 insertions(+), 22 deletions(-) create mode 100644 idea/idea-completion/testData/keywords/InAnnotationClassScope.kt create mode 100644 idea/idea-completion/testData/keywords/InEnumScope1.kt create mode 100644 idea/idea-completion/testData/keywords/InEnumScope2.kt create mode 100644 idea/idea-completion/testData/keywords/InInterfaceScope.kt create mode 100644 idea/idea-completion/testData/keywords/InObjectScope.kt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.kt index b56926bcb48..45979742ca1 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.kt @@ -95,7 +95,7 @@ public object ModifierCheckerCore { FINAL_KEYWORD to EnumSet.of(ENUM_CLASS, OBJECT) ) - private val possibleParentTargetMap = mapOf>( + val possibleParentTargetMap = mapOf>( INNER_KEYWORD to EnumSet.of(CLASS_ONLY, INNER_CLASS, LOCAL_CLASS, ENUM_CLASS, ENUM_ENTRY), OVERRIDE_KEYWORD to EnumSet.of(CLASS_ONLY, INNER_CLASS, LOCAL_CLASS, OBJECT, OBJECT_LITERAL, INTERFACE, ENUM_CLASS, ENUM_ENTRY), @@ -107,7 +107,7 @@ public object ModifierCheckerCore { COMPANION_KEYWORD to EnumSet.of(CLASS_ONLY, ENUM_CLASS, INTERFACE) ) - private val deprecatedParentTargetMap = mapOf>( + val deprecatedParentTargetMap = mapOf>( // Deprecated in M15 FINAL_KEYWORD to EnumSet.of(INTERFACE), PROTECTED_KEYWORD to EnumSet.of(OBJECT) 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 50dfd5e9e0b..721ab94ce25 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 @@ -28,6 +28,7 @@ import com.intellij.psi.filters.position.LeftNeighbour import com.intellij.psi.filters.position.PositionElementFilter import com.intellij.psi.tree.IElementType import com.intellij.psi.tree.TokenSet +import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget.* import org.jetbrains.kotlin.idea.completion.handlers.KotlinFunctionInsertHandler import org.jetbrains.kotlin.idea.completion.handlers.KotlinKeywordInsertHandler @@ -197,10 +198,10 @@ object KeywordCompletion { else -> { if (elementAt.parent !is JetModifierList) return true - val declaration = elementAt.parent.parent - val possibleTargets = when (declaration) { + val container = elementAt.parent.parent + val possibleTargets = when (container) { is JetParameter -> { - if (declaration.ownerFunction is JetPrimaryConstructor) + if (container.ownerFunction is JetPrimaryConstructor) listOf(VALUE_PARAMETER, MEMBER_PROPERTY) else listOf(VALUE_PARAMETER) @@ -208,14 +209,43 @@ object KeywordCompletion { is JetTypeParameter -> listOf(TYPE_PARAMETER) + is JetEnumEntry -> listOf(ENUM_ENTRY) + is JetClassBody -> listOf(CLASS_ONLY, INTERFACE, OBJECT, ENUM_CLASS, ANNOTATION_CLASS, INNER_CLASS, MEMBER_FUNCTION, MEMBER_PROPERTY, FUNCTION, PROPERTY) is JetFile -> listOf(CLASS_ONLY, INTERFACE, OBJECT, ENUM_CLASS, ANNOTATION_CLASS, TOP_LEVEL_FUNCTION, TOP_LEVEL_PROPERTY, FUNCTION, PROPERTY) + else -> null + } + val modifierTargets = ModifierCheckerCore.possibleTargetMap[keywordTokenType] + if (modifierTargets != null && possibleTargets != null && possibleTargets.none { it in modifierTargets }) return false + + val ownerDeclaration = container?.getParentOfType(strict = true) + val parentTarget = when (ownerDeclaration) { + null -> KotlinTarget.FILE + + is JetClass -> { + when { + ownerDeclaration.isInterface() -> KotlinTarget.INTERFACE + ownerDeclaration.isEnum() -> KotlinTarget.ENUM_CLASS + ownerDeclaration.isAnnotation() -> KotlinTarget.ANNOTATION_CLASS + ownerDeclaration.isInner() -> KotlinTarget.INNER_CLASS + else -> KotlinTarget.CLASS_ONLY + } + } + + is JetObjectDeclaration -> if (ownerDeclaration.isObjectLiteral()) KotlinTarget.OBJECT_LITERAL else KotlinTarget.OBJECT + else -> return true } - val modifierTargets = ModifierCheckerCore.possibleTargetMap[keywordTokenType] ?: return true - return possibleTargets.any { it in modifierTargets } + + val modifierParents = ModifierCheckerCore.possibleParentTargetMap[keywordTokenType] + if (modifierParents != null && parentTarget !in modifierParents) return false + + val deprecatedParents = ModifierCheckerCore.deprecatedParentTargetMap[keywordTokenType] + if (deprecatedParents != null && parentTarget in deprecatedParents) return false + + return true } } } diff --git a/idea/idea-completion/testData/keywords/AfterClasses.kt b/idea/idea-completion/testData/keywords/AfterClasses.kt index cf2676a8ecf..2efb6f3594a 100644 --- a/idea/idea-completion/testData/keywords/AfterClasses.kt +++ b/idea/idea-completion/testData/keywords/AfterClasses.kt @@ -21,7 +21,6 @@ class B { // EXIST: object // EXIST: open // EXIST: private -// EXIST: protected // EXIST: public // EXIST: interface // EXIST: val @@ -35,8 +34,4 @@ class B { // EXIST: external // EXIST: annotation // EXIST: const -/*TODO:*/ -// EXIST: inner -/*TODO:*/ -// EXIST: companion object // NOTHING_ELSE diff --git a/idea/idea-completion/testData/keywords/GlobalPropertyAccessors.kt b/idea/idea-completion/testData/keywords/GlobalPropertyAccessors.kt index 3acfad3f2e0..ad96ad3e87a 100644 --- a/idea/idea-completion/testData/keywords/GlobalPropertyAccessors.kt +++ b/idea/idea-completion/testData/keywords/GlobalPropertyAccessors.kt @@ -16,18 +16,15 @@ var a : Int // EXIST: final // EXIST: fun // EXIST: get -// EXIST: inner // EXIST: internal // EXIST: object // EXIST: open // EXIST: private -// EXIST: protected // EXIST: public // EXIST: set // EXIST: interface // EXIST: val // EXIST: var -// EXIST: companion object // EXIST: operator // EXIST: infix // EXIST: sealed diff --git a/idea/idea-completion/testData/keywords/InAnnotationClassScope.kt b/idea/idea-completion/testData/keywords/InAnnotationClassScope.kt new file mode 100644 index 00000000000..6a09d1e0c15 --- /dev/null +++ b/idea/idea-completion/testData/keywords/InAnnotationClassScope.kt @@ -0,0 +1,28 @@ +annotation class Test { + +} + +// EXIST: abstract +// EXIST: class +// EXIST: enum +// EXIST: final +// EXIST: fun +// EXIST: object +// EXIST: open +// EXIST: public +// EXIST: interface +// EXIST: val +// EXIST: var +// EXIST: constructor +// EXIST: init +// EXIST: operator +// EXIST: infix +// EXIST: sealed +// EXIST: lateinit +// EXIST: data +// EXIST: inline +// EXIST: tailrec +// EXIST: external +// EXIST: annotation +// EXIST: const +// NOTHING_ELSE diff --git a/idea/idea-completion/testData/keywords/InEnumScope1.kt b/idea/idea-completion/testData/keywords/InEnumScope1.kt new file mode 100644 index 00000000000..05ddfe91ad8 --- /dev/null +++ b/idea/idea-completion/testData/keywords/InEnumScope1.kt @@ -0,0 +1,5 @@ +enum class Test { + +} + +// NUMBER: 0 diff --git a/idea/idea-completion/testData/keywords/InEnumScope2.kt b/idea/idea-completion/testData/keywords/InEnumScope2.kt new file mode 100644 index 00000000000..8c2cec1482a --- /dev/null +++ b/idea/idea-completion/testData/keywords/InEnumScope2.kt @@ -0,0 +1,39 @@ +enum class Test { + ; + + +} + +// EXIST: abstract +// EXIST: enum +// EXIST: final +// EXIST: inner +// EXIST: internal +// EXIST: open +// EXIST: override +// EXIST: private +// EXIST: protected +// EXIST: public +// EXIST: companion object +// EXIST: operator +// EXIST: infix +// EXIST: sealed +// EXIST: lateinit +// EXIST: data +// EXIST: inline +// EXIST: tailrec +// EXIST: external +// EXIST: annotation +// EXIST: const +// EXIST: fun + +/* TODO: items below are not valid here */ +// EXIST: class +// EXIST: constructor +// EXIST: init +// EXIST: interface +// EXIST: object +// EXIST: val +// EXIST: var + +// NOTHING_ELSE diff --git a/idea/idea-completion/testData/keywords/InInterfaceScope.kt b/idea/idea-completion/testData/keywords/InInterfaceScope.kt new file mode 100644 index 00000000000..a4112851467 --- /dev/null +++ b/idea/idea-completion/testData/keywords/InInterfaceScope.kt @@ -0,0 +1,30 @@ +interface Test { + +} + +// EXIST: abstract +// EXIST: class +// EXIST: enum +// EXIST: fun +// EXIST: object +// EXIST: open +// EXIST: override +// EXIST: private +// EXIST: public +// EXIST: interface +// EXIST: val +// EXIST: var +// EXIST: constructor +// EXIST: init +// EXIST: companion object +// EXIST: operator +// EXIST: infix +// EXIST: sealed +// EXIST: lateinit +// EXIST: data +// EXIST: inline +// EXIST: tailrec +// EXIST: external +// EXIST: annotation +// EXIST: const +// NOTHING_ELSE diff --git a/idea/idea-completion/testData/keywords/InObjectScope.kt b/idea/idea-completion/testData/keywords/InObjectScope.kt new file mode 100644 index 00000000000..e5415258542 --- /dev/null +++ b/idea/idea-completion/testData/keywords/InObjectScope.kt @@ -0,0 +1,31 @@ +object Test { + +} + +// EXIST: abstract +// EXIST: class +// EXIST: enum +// EXIST: final +// EXIST: fun +// EXIST: internal +// EXIST: object +// EXIST: open +// EXIST: override +// EXIST: private +// EXIST: public +// EXIST: interface +// EXIST: val +// EXIST: var +// EXIST: constructor +// EXIST: init +// EXIST: operator +// EXIST: infix +// EXIST: sealed +// EXIST: lateinit +// EXIST: data +// EXIST: inline +// EXIST: tailrec +// EXIST: external +// EXIST: annotation +// EXIST: const +// NOTHING_ELSE diff --git a/idea/idea-completion/testData/keywords/InTopScopeAfterPackage.kt b/idea/idea-completion/testData/keywords/InTopScopeAfterPackage.kt index d27f2088ffb..1cd1c56dd58 100644 --- a/idea/idea-completion/testData/keywords/InTopScopeAfterPackage.kt +++ b/idea/idea-completion/testData/keywords/InTopScopeAfterPackage.kt @@ -8,17 +8,14 @@ package Test // EXIST: final // EXIST: fun // EXIST: import -// EXIST: inner // EXIST: internal // EXIST: object // EXIST: open // EXIST: private -// EXIST: protected // EXIST: public // EXIST: interface // EXIST: val // EXIST: var -// EXIST: companion object // EXIST: operator // EXIST: infix // EXIST: sealed diff --git a/idea/idea-completion/testData/keywords/PrefixMatcher.kt b/idea/idea-completion/testData/keywords/PrefixMatcher.kt index 9e9e13354e8..a9c284702b1 100644 --- a/idea/idea-completion/testData/keywords/PrefixMatcher.kt +++ b/idea/idea-completion/testData/keywords/PrefixMatcher.kt @@ -4,6 +4,5 @@ p // EXIST: package // EXIST: private -// EXIST: protected // EXIST: public // NOTHING_ELSE diff --git a/idea/idea-completion/testData/keywords/TopScope.kt b/idea/idea-completion/testData/keywords/TopScope.kt index 53526a46246..28ba4f8795c 100644 --- a/idea/idea-completion/testData/keywords/TopScope.kt +++ b/idea/idea-completion/testData/keywords/TopScope.kt @@ -6,18 +6,15 @@ // EXIST: final // EXIST: fun // EXIST: import -// EXIST: inner // EXIST: internal // EXIST: object // EXIST: open // EXIST: package // EXIST: private -// EXIST: protected // EXIST: public // EXIST: interface // EXIST: val // EXIST: var -// EXIST: companion object // EXIST: operator // EXIST: infix // EXIST: sealed 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 3980615efd9..bc8cbebf409 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 @@ -119,6 +119,12 @@ public class KeywordCompletionTestGenerated extends AbstractKeywordCompletionTes doTest(fileName); } + @TestMetadata("InAnnotationClassScope.kt") + public void testInAnnotationClassScope() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/InAnnotationClassScope.kt"); + doTest(fileName); + } + @TestMetadata("InArgumentList.kt") public void testInArgumentList() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/InArgumentList.kt"); @@ -173,6 +179,18 @@ public class KeywordCompletionTestGenerated extends AbstractKeywordCompletionTes doTest(fileName); } + @TestMetadata("InEnumScope1.kt") + public void testInEnumScope1() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/InEnumScope1.kt"); + doTest(fileName); + } + + @TestMetadata("InEnumScope2.kt") + public void testInEnumScope2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/InEnumScope2.kt"); + doTest(fileName); + } + @TestMetadata("InFunctionExpressionBody.kt") public void testInFunctionExpressionBody() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/InFunctionExpressionBody.kt"); @@ -203,6 +221,12 @@ public class KeywordCompletionTestGenerated extends AbstractKeywordCompletionTes doTest(fileName); } + @TestMetadata("InInterfaceScope.kt") + public void testInInterfaceScope() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/InInterfaceScope.kt"); + doTest(fileName); + } + @TestMetadata("InMemberFunParametersList.kt") public void testInMemberFunParametersList() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/InMemberFunParametersList.kt"); @@ -221,6 +245,12 @@ public class KeywordCompletionTestGenerated extends AbstractKeywordCompletionTes doTest(fileName); } + @TestMetadata("InObjectScope.kt") + public void testInObjectScope() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/InObjectScope.kt"); + doTest(fileName); + } + @TestMetadata("InParameterDefaultValue.kt") public void testInParameterDefaultValue() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/keywords/InParameterDefaultValue.kt");