From 0e045b947800bf6c22a9e20b866b8690620a2f64 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Wed, 17 Jun 2015 18:53:25 +0300 Subject: [PATCH] Completion of parameter name+type works for val/var parameters --- .../idea/completion/CompletionSession.kt | 36 +++++++++--------- .../ParameterNameAndTypeCompletion.kt | 37 +++++++++++++++++-- .../parameterNameAndType/ValParameter.kt | 11 ++++++ .../parameterNameAndType/VarParameter.kt | 11 ++++++ .../test/JSBasicCompletionTestGenerated.java | 12 ++++++ .../test/JvmBasicCompletionTestGenerated.java | 12 ++++++ 6 files changed, 97 insertions(+), 22 deletions(-) create mode 100644 idea/idea-completion/testData/basic/common/parameterNameAndType/ValParameter.kt create mode 100644 idea/idea-completion/testData/basic/common/parameterNameAndType/VarParameter.kt diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt index c8f9564bb21..aa6642fcaa1 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt @@ -263,13 +263,14 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration, resultSet: CompletionResultSet) : CompletionSessionBase(configuration, parameters, resultSet) { - public enum class CompletionKind { - KEYWORDS_ONLY, - NAMED_ARGUMENTS_ONLY, - ALL, - TYPES, - ANNOTATION_TYPES, - ANNOTATION_TYPES_OR_PARAMETER_NAME + public enum class CompletionKind(val classKindFilter: ((ClassKind) -> Boolean)?) { + KEYWORDS_ONLY(classKindFilter = null), + NAMED_ARGUMENTS_ONLY(classKindFilter = null), + ALL(classKindFilter = { it != ClassKind.ENUM_ENTRY }), + TYPES(classKindFilter = { it != ClassKind.ENUM_ENTRY }), + ANNOTATION_TYPES(classKindFilter = { it == ClassKind.ANNOTATION_CLASS }), + ANNOTATION_TYPES_OR_PARAMETER_NAME(classKindFilter = { it == ClassKind.ANNOTATION_CLASS }), + PARAMETER_NAME(classKindFilter = null) } public val completionKind: CompletionKind = calcCompletionKind() @@ -284,12 +285,12 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration, CompletionKind.ALL -> DescriptorKindFilter(DescriptorKindFilter.ALL_KINDS_MASK) - CompletionKind.NAMED_ARGUMENTS_ONLY, CompletionKind.KEYWORDS_ONLY -> + CompletionKind.NAMED_ARGUMENTS_ONLY, CompletionKind.KEYWORDS_ONLY, CompletionKind.PARAMETER_NAME -> null } - private val parameterNameAndTypeCompletion = if (completionKind == CompletionKind.ANNOTATION_TYPES_OR_PARAMETER_NAME) - ParameterNameAndTypeCompletion(collector, lookupElementFactory, prefixMatcher) + private val parameterNameAndTypeCompletion = if (completionKind == CompletionKind.PARAMETER_NAME || completionKind == CompletionKind.ANNOTATION_TYPES_OR_PARAMETER_NAME) + ParameterNameAndTypeCompletion(collector, lookupElementFactory, prefixMatcher, resolutionFacade) else null @@ -299,7 +300,11 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration, } if (reference == null) { - return CompletionKind.KEYWORDS_ONLY + val parameter = position.getParent() as? JetParameter + return if (parameter != null && position == parameter.getNameIdentifier()) + CompletionKind.PARAMETER_NAME + else + CompletionKind.KEYWORDS_ONLY } val annotationEntry = position.getStrictParentOfType() @@ -333,7 +338,7 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration, if (completionKind != CompletionKind.NAMED_ARGUMENTS_ONLY) { collector.addDescriptorElements(referenceVariants, suppressAutoInsertion = false) - parameterNameAndTypeCompletion?.addFromImports(reference!!.expression, bindingContext, { isVisibleDescriptor(it) }) + parameterNameAndTypeCompletion?.addFromImports(position, bindingContext, { isVisibleDescriptor(it) }) val keywordsPrefix = prefix.substringBefore('@') // if there is '@' in the prefix - use shorter prefix to not loose 'this' etc KeywordCompletion.complete(expression ?: parameters.getPosition(), keywordsPrefix) { lookupElement -> @@ -402,12 +407,7 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration, flushToResultSet() if (shouldRunTopLevelCompletion()) { - addAllClasses { - if (completionKind != CompletionKind.ANNOTATION_TYPES && completionKind != CompletionKind.ANNOTATION_TYPES_OR_PARAMETER_NAME) - it != ClassKind.ENUM_ENTRY - else - it == ClassKind.ANNOTATION_CLASS - } + completionKind.classKindFilter?.let { addAllClasses(it) } if (completionKind == CompletionKind.ALL) { collector.addDescriptorElements(getTopLevelCallables(), suppressAutoInsertion = true) diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ParameterNameAndTypeCompletion.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ParameterNameAndTypeCompletion.kt index 269ebb6bc9e..eafdf18a5be 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ParameterNameAndTypeCompletion.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ParameterNameAndTypeCompletion.kt @@ -23,29 +23,37 @@ import com.intellij.codeInsight.lookup.LookupElement import com.intellij.codeInsight.lookup.LookupElementDecorator import com.intellij.codeInsight.lookup.LookupElementPresentation import com.intellij.psi.PsiClass +import com.intellij.psi.PsiElement import com.intellij.psi.codeStyle.CodeStyleSettingsManager +import org.jetbrains.kotlin.descriptors.ClassDescriptorWithResolutionScopes import org.jetbrains.kotlin.descriptors.ClassifierDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.idea.caches.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.core.KotlinIndicesHelper import org.jetbrains.kotlin.idea.core.formatter.JetCodeStyleSettings import org.jetbrains.kotlin.idea.core.refactoring.EmptyValidator import org.jetbrains.kotlin.idea.core.refactoring.JetNameSuggester -import org.jetbrains.kotlin.psi.JetSimpleNameExpression +import org.jetbrains.kotlin.psi.JetClassOrObject +import org.jetbrains.kotlin.psi.JetExpression +import org.jetbrains.kotlin.psi.JetFile +import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter +import org.jetbrains.kotlin.resolve.scopes.JetScope import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered class ParameterNameAndTypeCompletion( private val collector: LookupElementsCollector, private val lookupElementFactory: LookupElementFactory, - private val prefixMatcher: PrefixMatcher + private val prefixMatcher: PrefixMatcher, + private val resolutionFacade: ResolutionFacade ) { private val modifiedPrefixMatcher = prefixMatcher.cloneWithPrefix(prefixMatcher.getPrefix().capitalize()) - public fun addFromImports(nameExpression: JetSimpleNameExpression, bindingContext: BindingContext, visibilityFilter: (DeclarationDescriptor) -> Boolean) { + public fun addFromImports(context: PsiElement, bindingContext: BindingContext, visibilityFilter: (DeclarationDescriptor) -> Boolean) { if (prefixMatcher.getPrefix().isEmpty()) return - val resolutionScope = bindingContext[BindingContext.RESOLUTION_SCOPE, nameExpression] ?: return + val resolutionScope = context.getResolutionScope(bindingContext) val classifiers = resolutionScope.getDescriptorsFiltered(DescriptorKindFilter.NON_SINGLETON_CLASSIFIERS, modifiedPrefixMatcher.asNameFilter()) for (classifier in classifiers) { @@ -55,6 +63,27 @@ class ParameterNameAndTypeCompletion( } } + private fun PsiElement.getResolutionScope(bindingContext: BindingContext): JetScope { + for (parent in parentsWithSelf) { + if (parent is JetExpression) { + val scope = bindingContext[BindingContext.RESOLUTION_SCOPE, parent] + if (scope != null) return scope + } + + if (parent is JetClassOrObject) { + val classDescriptor = bindingContext[BindingContext.CLASS, parent] as? ClassDescriptorWithResolutionScopes + if (classDescriptor != null) { + return classDescriptor.getScopeForMemberDeclarationResolution() + } + } + + if (parent is JetFile) { + return resolutionFacade.getFileTopLevelScope(parent) + } + } + error("Not in JetFile") + } + public fun addAll(parameters: CompletionParameters, indicesHelper: KotlinIndicesHelper) { if (prefixMatcher.getPrefix().isEmpty()) return diff --git a/idea/idea-completion/testData/basic/common/parameterNameAndType/ValParameter.kt b/idea/idea-completion/testData/basic/common/parameterNameAndType/ValParameter.kt new file mode 100644 index 00000000000..5667ddd7dc2 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/parameterNameAndType/ValParameter.kt @@ -0,0 +1,11 @@ +package pack + +class FooBar + +class Boo + +class C(val b) + +// EXIST: { lookupString: "bar", itemText: "bar: FooBar", tailText: " (pack)" } +// EXIST: { lookupString: "fooBar", itemText: "fooBar: FooBar", tailText: " (pack)" } +// EXIST: { lookupString: "boo", itemText: "boo: Boo", tailText: " (pack)" } diff --git a/idea/idea-completion/testData/basic/common/parameterNameAndType/VarParameter.kt b/idea/idea-completion/testData/basic/common/parameterNameAndType/VarParameter.kt new file mode 100644 index 00000000000..68880017a92 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/parameterNameAndType/VarParameter.kt @@ -0,0 +1,11 @@ +package pack + +class FooBar + +class C(private var b) { + class Boo +} + +// EXIST: { lookupString: "bar", itemText: "bar: FooBar", tailText: " (pack)" } +// EXIST: { lookupString: "fooBar", itemText: "fooBar: FooBar", tailText: " (pack)" } +// EXIST: { lookupString: "boo", itemText: "boo: Boo", tailText: " (pack.C)" } diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java index 7337e37100d..6d518b10d7e 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java @@ -1427,6 +1427,18 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/parameterNameAndType/Simple.kt"); doTest(fileName); } + + @TestMetadata("ValParameter.kt") + public void testValParameter() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/parameterNameAndType/ValParameter.kt"); + doTest(fileName); + } + + @TestMetadata("VarParameter.kt") + public void testVarParameter() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/parameterNameAndType/VarParameter.kt"); + doTest(fileName); + } } @TestMetadata("idea/idea-completion/testData/basic/common/shadowing") diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java index 33b3cd9b387..b23995d0529 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java @@ -1427,6 +1427,18 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/parameterNameAndType/Simple.kt"); doTest(fileName); } + + @TestMetadata("ValParameter.kt") + public void testValParameter() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/parameterNameAndType/ValParameter.kt"); + doTest(fileName); + } + + @TestMetadata("VarParameter.kt") + public void testVarParameter() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/parameterNameAndType/VarParameter.kt"); + doTest(fileName); + } } @TestMetadata("idea/idea-completion/testData/basic/common/shadowing")