From b771f9eea44a37dd7a68c08dc8053f0bb1556cde Mon Sep 17 00:00:00 2001 From: Ilya Muradyan Date: Tue, 4 May 2021 04:40:00 +0300 Subject: [PATCH] [REPL] Add completion for the call named parameters --- .../ReplCompletionAndErrorsAnalysisTest.kt | 18 +++++++ .../compiler/impl/KJvmReplCompleter.kt | 52 +++++++++++++------ 2 files changed, 53 insertions(+), 17 deletions(-) diff --git a/plugins/scripting/scripting-ide-services-test/test/org/jetbrains/kotlin/scripting/ide_services/ReplCompletionAndErrorsAnalysisTest.kt b/plugins/scripting/scripting-ide-services-test/test/org/jetbrains/kotlin/scripting/ide_services/ReplCompletionAndErrorsAnalysisTest.kt index 95c45948cc6..068cc891eaf 100644 --- a/plugins/scripting/scripting-ide-services-test/test/org/jetbrains/kotlin/scripting/ide_services/ReplCompletionAndErrorsAnalysisTest.kt +++ b/plugins/scripting/scripting-ide-services-test/test/org/jetbrains/kotlin/scripting/ide_services/ReplCompletionAndErrorsAnalysisTest.kt @@ -109,6 +109,24 @@ class ReplCompletionAndErrorsAnalysisTest : TestCase() { } } + @Test + fun testFunctionArgumentNames() = test { + run { + doCompile + code = """fun _sf(_someInt: Int = 42, _someString: String = "s") = 1""" + } + run { + doComplete + code = """_sf(_s""" + cursor = code.length + expect { + addCompletion("_sf(", "_sf(Int = ..., String = ...)", "Int", "method") + addCompletion("_someInt = ", "_someInt", "Int", "parameter") + addCompletion("_someString = ", "_someString", "String", "parameter") + } + } + } + @Test fun testExtensionMethods() = test { run { diff --git a/plugins/scripting/scripting-ide-services/src/org/jetbrains/kotlin/scripting/ide_services/compiler/impl/KJvmReplCompleter.kt b/plugins/scripting/scripting-ide-services/src/org/jetbrains/kotlin/scripting/ide_services/compiler/impl/KJvmReplCompleter.kt index 485382aac0d..10e5df292b2 100644 --- a/plugins/scripting/scripting-ide-services/src/org/jetbrains/kotlin/scripting/ide_services/compiler/impl/KJvmReplCompleter.kt +++ b/plugins/scripting/scripting-ide-services/src/org/jetbrains/kotlin/scripting/ide_services/compiler/impl/KJvmReplCompleter.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.endOffset +import org.jetbrains.kotlin.psi.psiUtil.getParentOfType import org.jetbrains.kotlin.psi.psiUtil.quoteIfNeeded import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.renderer.ClassifierNamePolicy @@ -36,7 +37,6 @@ import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.asFlexibleType import org.jetbrains.kotlin.types.isFlexible import java.io.File -import java.util.* import kotlin.script.experimental.api.ScriptCompilationConfiguration import kotlin.script.experimental.api.SourceCodeCompletionVariant @@ -115,21 +115,35 @@ private class KJvmReplCompleter( ) return@gen } + val containingCallId = simpleExpression.getParentOfType(true)?.calleeExpression?.text + fun Name.test(checkAgainstContainingCall: Boolean): Boolean { + if (isSpecial) return false + if (nameFilter(identifier, prefix)) return true + return checkAgainstContainingCall && containingCallId?.let { nameFilter(identifier, it) } == true + } + isSortNeeded = false - descriptors = ReferenceVariantsHelper( - bindingContext, - resolutionFacade, - moduleDescriptor, - VisibilityFilter(inDescriptor) - ).getReferenceVariants( - simpleExpression, - DescriptorKindFilter.ALL, - { name: Name -> !name.isSpecial && nameFilter(name.identifier, prefix) }, - filterOutJavaGettersAndSetters = true, - filterOutShadowed = filterOutShadowedDescriptors, // setting to true makes it slower up to 4 times - excludeNonInitializedVariable = true, - useReceiverType = null - ) + descriptors = ArrayList().also { result -> + ReferenceVariantsHelper( + bindingContext, + resolutionFacade, + moduleDescriptor, + VisibilityFilter(inDescriptor) + ).getReferenceVariants( + simpleExpression, + DescriptorKindFilter.ALL, + { it.test(true) }, + filterOutJavaGettersAndSetters = true, + filterOutShadowed = filterOutShadowedDescriptors, // setting to true makes it slower up to 4 times + excludeNonInitializedVariable = true, + useReceiverType = null + ).forEach { descriptor -> + if (descriptor.name.test(false)) result.add(descriptor) + if (descriptor is CallableDescriptor && containingCallId == descriptor.name.identifier) { + descriptor.valueParameters.filterTo(result) { it.name.test(false) } + } + } + } } else if (element is KtStringTemplateExpression) { if (element.hasInterpolation()) { @@ -348,7 +362,7 @@ private class KJvmReplCompleter( is ClassDescriptor -> "class" is PackageFragmentDescriptor -> "package" is PackageViewDescriptor -> "package" - is ValueParameterDescriptor -> "genericValue" + is ValueParameterDescriptor -> "parameter" is TypeParameterDescriptorImpl -> "class" else -> "" } @@ -396,13 +410,17 @@ private class KJvmReplCompleter( val outType = descriptor.type typeText = RENDERER.renderType(outType) + if (descriptor is ValueParameterDescriptor) { + completionText = "$rawDescriptorName = " + } } else if (descriptor is ClassDescriptor) { val declaredIn = descriptor.containingDeclaration tailText = " (" + DescriptorUtils.getFqName(declaredIn) + ")" } else { typeText = RENDERER.render(descriptor) } - tailText = if (typeText.isEmpty()) tailText else typeText + + tailText = typeText.ifEmpty { tailText } if (completionText.isEmpty()) { completionText = presentableText