From b5dd2cc540a29eccc44b47a82a643ad210d9fbd0 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Thu, 16 Mar 2017 20:36:08 +0300 Subject: [PATCH] Completion of lambda parameters Also changed policy for sorting of smart completion items in basic completion #KT-16800 Fixed #KT-12002 Fixed --- .../idea/util/IdeDescriptorRenderers.kt | 1 + .../idea/completion/BasicCompletionSession.kt | 1 - .../completion/LambdaSignatureTemplates.kt | 197 ++++++++++++++++++ .../idea/completion/LookupElementFactory.kt | 15 +- .../completion/NamedArgumentCompletion.kt | 3 +- .../kotlin/idea/completion/Weighers.kt | 20 +- .../completion/handlers/GenerateLambda.kt | 150 ------------- .../handlers/KotlinFunctionInsertHandler.kt | 6 +- .../idea/completion/smart/LambdaItems.kt | 68 ++++-- .../completion/smart/LambdaSignatureItems.kt | 87 ++++++++ .../idea/completion/smart/SmartCompletion.kt | 2 + .../kotlin/idea/completion/smart/Utils.kt | 2 + .../basic/common/namedArguments/AfterBrace.kt | 2 +- .../basic/common/namedArguments/AfterComma.kt | 2 +- .../common/namedArguments/AfterVararg.kt | 2 +- .../common/namedArguments/CompactTypeNames.kt | 4 +- .../namedArguments/InParameterExpression.kt | 4 +- .../NamedArgumentsFromOverloads.kt | 2 +- .../namedArguments/NoAlreadyUsedParameters.kt | 8 +- .../NoParamsFromUnapplicableOverload.kt | 8 +- .../namedArguments/NotOnlyNamedArguments.kt | 6 +- .../namedArguments/NotOnlyNamedArguments2.kt | 6 +- .../common/namedArguments/OfConstructor.kt | 4 +- .../namedArguments/OnlyNamedArguments.kt | 6 +- .../namedArguments/WithParameterExpression.kt | 4 +- .../basic/withLib/NamedArgumentsKotlin.kt | 2 +- .../NamedParametersCompletionOnEqual.kt.after | 2 +- .../handlers/charFilter/NamedParameter1.kt | 2 +- .../charFilter/NamedParameter1.kt.after | 4 +- .../handlers/charFilter/NamedParameter2.kt | 2 +- .../charFilter/NamedParameter2.kt.after | 4 +- .../testData/handlers/smart/lambda/3.kt | 2 +- .../testData/handlers/smart/lambda/3.kt.after | 2 +- .../testData/handlers/smart/lambda/4.kt | 2 +- .../testData/handlers/smart/lambda/4.kt.after | 2 +- .../testData/smart/AfterEmptyArgument.kt | 4 +- .../testData/smart/AfterNamedArgument.kt | 4 +- .../testData/smart/functionLiterals/2.kt | 4 +- .../testData/smart/functionLiterals/3.kt | 4 +- .../testData/smart/functionLiterals/5.kt | 4 +- .../ExplicitParameterTypesRequired.kt | 11 + .../OutsideCallParenthesis1.kt | 6 +- .../OutsideCallParenthesis2.kt | 3 +- .../OutsideCallParenthesis3.kt | 3 +- .../OutsideCallParenthesis4.kt | 3 +- .../OutsideCallParenthesis5.kt | 3 +- .../OutsideCallParenthesis6.kt | 3 +- .../OutsideCallParenthesis7.kt | 3 +- .../OutsideCallParenthesis8.kt | 3 +- .../OutsideCallParenthesisAndVararg1.kt | 3 +- .../OutsideCallParenthesisAndVararg2.kt | 3 +- .../ExplicitParameterTypesRequired.kt | 11 + .../lambdaSignature/MultipleParameters.kt | 7 + .../smart/lambdaSignature/NotAfterComma.kt | 5 + .../smart/lambdaSignature/NotInBody.kt | 7 + .../smart/lambdaSignature/SingleParameter.kt | 7 + .../weighers/basic/LambdaSignature.kt | 8 + .../weighers/basic/NamedParameters.kt | 4 +- .../weighers/basic/NamedParameters2.kt | 2 +- .../weighers/basic/NamedParameters3.kt | 2 +- .../basic/expectedInfo/MultiArgsItem.kt | 2 +- .../smart/CallableReference_NothingLast.kt | 3 +- .../weighers/smart/FunctionExpected.kt | 3 +- .../test/JvmSmartCompletionTestGenerated.java | 45 ++++ .../handlers/BasicCompletionHandlerTest.kt | 4 +- .../BasicCompletionWeigherTestGenerated.java | 6 + 66 files changed, 558 insertions(+), 256 deletions(-) create mode 100644 idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LambdaSignatureTemplates.kt delete mode 100644 idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/GenerateLambda.kt create mode 100644 idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/LambdaSignatureItems.kt create mode 100644 idea/idea-completion/testData/smart/functionLiterals/ExplicitParameterTypesRequired.kt create mode 100644 idea/idea-completion/testData/smart/lambdaSignature/ExplicitParameterTypesRequired.kt create mode 100644 idea/idea-completion/testData/smart/lambdaSignature/MultipleParameters.kt create mode 100644 idea/idea-completion/testData/smart/lambdaSignature/NotAfterComma.kt create mode 100644 idea/idea-completion/testData/smart/lambdaSignature/NotInBody.kt create mode 100644 idea/idea-completion/testData/smart/lambdaSignature/SingleParameter.kt create mode 100644 idea/idea-completion/testData/weighers/basic/LambdaSignature.kt diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/IdeDescriptorRenderers.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/IdeDescriptorRenderers.kt index f4c7b3b338b..ddeda1be9d0 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/IdeDescriptorRenderers.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/IdeDescriptorRenderers.kt @@ -65,5 +65,6 @@ object IdeDescriptorRenderers { @JvmField val SOURCE_CODE_SHORT_NAMES_IN_TYPES: DescriptorRenderer = BASE.withOptions { classifierNamePolicy = ClassifierNamePolicy.SHORT typeNormalizer = { APPROXIMATE_FLEXIBLE_TYPES(unwrapAnonymousType(it)) } + modifiers -= DescriptorRendererModifier.ANNOTATIONS } } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicCompletionSession.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicCompletionSession.kt index 5fea1cd7861..f20d1d66db0 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicCompletionSession.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicCompletionSession.kt @@ -150,7 +150,6 @@ class BasicCompletionSession( val smartCompletionInBasicWeigher = SmartCompletionInBasicWeigher(smartCompletion, callTypeAndReceiver, resolutionFacade, bindingContext) sorter = sorter.weighBefore(KindWeigher.toString(), smartCompletionInBasicWeigher, - SmartCompletionPriorityWeigher, CallableReferenceWeigher(callTypeAndReceiver.callType)) } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LambdaSignatureTemplates.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LambdaSignatureTemplates.kt new file mode 100644 index 00000000000..233b9a1986a --- /dev/null +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LambdaSignatureTemplates.kt @@ -0,0 +1,197 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.completion + +import com.intellij.codeInsight.completion.InsertionContext +import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.codeInsight.lookup.LookupElementBuilder +import com.intellij.codeInsight.template.* +import com.intellij.openapi.command.CommandProcessor +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.TextRange +import com.intellij.psi.PsiDocumentManager +import com.intellij.psi.util.PsiTreeUtil +import org.jetbrains.kotlin.builtins.extractParameterNameFromFunctionTypeArgument +import org.jetbrains.kotlin.builtins.getValueParameterTypesFromFunctionType +import org.jetbrains.kotlin.builtins.isFunctionType +import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade +import org.jetbrains.kotlin.idea.core.ExpectedInfos +import org.jetbrains.kotlin.idea.core.KotlinNameSuggester +import org.jetbrains.kotlin.idea.core.fuzzyType +import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers +import org.jetbrains.kotlin.idea.util.application.executeWriteCommand +import org.jetbrains.kotlin.psi.KtExpression +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.renderer.DescriptorRendererModifier +import org.jetbrains.kotlin.renderer.render +import org.jetbrains.kotlin.resolve.calls.util.getValueParametersCountFromFunctionType +import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.TypeProjection + +object LambdaSignatureTemplates { + fun insertTemplate( + context: InsertionContext, + placeholderRange: TextRange, + lambdaType: KotlinType, + explicitParameterTypes: Boolean, + signatureOnly: Boolean + ) { + // we start template later to not interfere with insertion of tail type + val commandProcessor = CommandProcessor.getInstance() + val commandName = commandProcessor.currentCommandName!! + val commandGroupId = commandProcessor.currentCommandGroupId + + val rangeMarker = context.document.createRangeMarker(placeholderRange) + + context.setLaterRunnable { + context.project.executeWriteCommand(commandName, groupId = commandGroupId) { + try { + if (rangeMarker.isValid) { + context.document.deleteString(rangeMarker.startOffset, rangeMarker.endOffset) + context.editor.caretModel.moveToOffset(rangeMarker.startOffset) + val template = buildTemplate(lambdaType, signatureOnly, explicitParameterTypes, context.project) + TemplateManager.getInstance(context.project).startTemplate(context.editor, template) + } + } + finally { + rangeMarker.dispose() + } + } + } + } + + val DEFAULT_LAMBDA_PRESENTATION = "{...}" + + enum class SignaturePresentation { + NAMES, + NAMES_OR_TYPES, + NAMES_AND_TYPES + } + + fun lambdaPresentation(lambdaType: KotlinType, presentationKind: SignaturePresentation): String { + return "{ " + signaturePresentation(lambdaType, presentationKind) + " ... }" + } + + fun signaturePresentation(lambdaType: KotlinType, presentationKind: SignaturePresentation): String { + fun typePresentation(type: KotlinType) = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(type) + + fun parameterPresentation(parameterType: KotlinType): String { + val name = parameterType.extractParameterNameFromFunctionTypeArgument()?.render() + return when (presentationKind) { + SignaturePresentation.NAMES -> name ?: nameSuggestion(parameterType) + SignaturePresentation.NAMES_OR_TYPES -> name ?: typePresentation(parameterType) + SignaturePresentation.NAMES_AND_TYPES -> "${name ?: nameSuggestion(parameterType)}: ${typePresentation(parameterType)}" + } + } + + return functionParameterTypes(lambdaType) + .map(::parameterPresentation) + .joinToString(", ") + " ->" + } + + fun explicitParameterTypesRequired(file: KtFile, placeholderRange: TextRange, lambdaType: KotlinType): Boolean { + PsiDocumentManager.getInstance(file.project).commitAllDocuments() + val expression = PsiTreeUtil.findElementOfClassAtRange(file, placeholderRange.startOffset, placeholderRange.endOffset, KtExpression::class.java) + ?: return false + + val resolutionFacade = file.getResolutionFacade() + val bindingContext = resolutionFacade.analyze(expression, BodyResolveMode.PARTIAL) + val expectedInfos = ExpectedInfos(bindingContext, resolutionFacade, indicesHelper = null, useHeuristicSignatures = false).calculate(expression) + val functionTypes = expectedInfos + .mapNotNull { it.fuzzyType?.type } + .filter(KotlinType::isFunctionType) + .toSet() + return explicitParameterTypesRequired(functionTypes, lambdaType) + } + + fun explicitParameterTypesRequired(expectedFunctionTypes: Set, lambdaType: KotlinType): Boolean { + if (expectedFunctionTypes.size <= 1) return false + val lambdaParameterCount = getValueParametersCountFromFunctionType(lambdaType) + return expectedFunctionTypes.filter { getValueParametersCountFromFunctionType(it) == lambdaParameterCount }.size > 1 + } + + private val TYPE_RENDERER = IdeDescriptorRenderers.SOURCE_CODE.withOptions { + modifiers -= DescriptorRendererModifier.ANNOTATIONS + } + + private fun buildTemplate( + lambdaType: KotlinType, + signatureOnly: Boolean, + explicitParameterTypes: Boolean, + project: Project + ): Template { + val parameterTypes = functionParameterTypes(lambdaType) + + val manager = TemplateManager.getInstance(project) + + val template = manager.createTemplate("", "") + template.isToShortenLongNames = true + //template.setToReformat(true) //TODO + if (!signatureOnly) { + template.addTextSegment("{ ") + } + + for ((i, parameterType) in parameterTypes.withIndex()) { + if (i > 0) { + template.addTextSegment(", ") + } + //TODO: check for names in scope + val parameterName = parameterType.extractParameterNameFromFunctionTypeArgument()?.render() + val nameExpression = if (parameterName != null) { + object : Expression() { + override fun calculateResult(context: ExpressionContext?) = TextResult(parameterName) + override fun calculateQuickResult(context: ExpressionContext?): Result? = TextResult(parameterName) + override fun calculateLookupItems(context: ExpressionContext?) = emptyArray() + } + } + else { + val nameSuggestions = nameSuggestions(parameterType) + object : Expression() { + override fun calculateResult(context: ExpressionContext?) = TextResult(nameSuggestions[0]) + override fun calculateQuickResult(context: ExpressionContext?): Result? = null + override fun calculateLookupItems(context: ExpressionContext?) + = nameSuggestions.map { LookupElementBuilder.create(it) }.toTypedArray() + } + } + template.addVariable(nameExpression, true) + + if (explicitParameterTypes) { + template.addTextSegment(": " + TYPE_RENDERER.renderType(parameterType)) + } + } + + template.addTextSegment(" -> ") + template.addEndVariable() + + if (!signatureOnly) { + template.addTextSegment(" }") + } + else { + template.addTextSegment(" ") //TODO: no additional space if space ahead + } + + return template + } + + private fun nameSuggestions(parameterType: KotlinType) = KotlinNameSuggester.suggestNamesByType(parameterType, { true }, "p") + private fun nameSuggestion(parameterType: KotlinType) = nameSuggestions(parameterType)[0] + + private fun functionParameterTypes(functionType: KotlinType): List { + return functionType.getValueParameterTypesFromFunctionType().map(TypeProjection::getType) + } +} diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementFactory.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementFactory.kt index b9473be9b14..abc14bd843b 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementFactory.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementFactory.kt @@ -28,7 +28,6 @@ import org.jetbrains.kotlin.builtins.isFunctionType import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.idea.completion.handlers.GenerateLambdaInfo import org.jetbrains.kotlin.idea.completion.handlers.KotlinFunctionInsertHandler -import org.jetbrains.kotlin.idea.completion.handlers.lambdaPresentation import org.jetbrains.kotlin.idea.core.moveCaret import org.jetbrains.kotlin.idea.util.CallType import org.jetbrains.kotlin.idea.util.ReceiverType @@ -146,7 +145,7 @@ class LookupElementFactory( val insertHandler = insertHandlerProvider.insertHandler(descriptor) as KotlinFunctionInsertHandler.Normal if (insertHandler.lambdaInfo == null) { val functionParameterCount = getValueParametersCountFromFunctionType(parameterType) - add(createFunctionCallElementWithLambda(descriptor, parameterType, functionParameterCount > 1, useReceiverTypes)) + add(createFunctionCallElementWithLambda(descriptor, parameterType, useReceiverTypes, explicitLambdaParameters = functionParameterCount > 1)) } if (isSingleParameter) { @@ -161,11 +160,19 @@ class LookupElementFactory( } } - private fun createFunctionCallElementWithLambda(descriptor: FunctionDescriptor, parameterType: KotlinType, explicitLambdaParameters: Boolean, useReceiverTypes: Boolean): LookupElement { + private fun createFunctionCallElementWithLambda( + descriptor: FunctionDescriptor, + parameterType: KotlinType, + useReceiverTypes: Boolean, + explicitLambdaParameters: Boolean + ): LookupElement { var lookupElement = createLookupElement(descriptor, useReceiverTypes) val inputTypeArguments = (insertHandlerProvider.insertHandler(descriptor) as KotlinFunctionInsertHandler.Normal).inputTypeArguments val lambdaInfo = GenerateLambdaInfo(parameterType, explicitLambdaParameters) - val lambdaPresentation = lambdaPresentation(if (explicitLambdaParameters) parameterType else null) + val lambdaPresentation = if (explicitLambdaParameters) + LambdaSignatureTemplates.lambdaPresentation(parameterType, LambdaSignatureTemplates.SignaturePresentation.NAMES_OR_TYPES) + else + LambdaSignatureTemplates.DEFAULT_LAMBDA_PRESENTATION // render only the last parameter because all other should be optional and will be omitted var parametersRenderer = BasicLookupElementFactory.SHORT_NAMES_RENDERER diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/NamedArgumentCompletion.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/NamedArgumentCompletion.kt index 9c78ca6cf12..3a52b95101a 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/NamedArgumentCompletion.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/NamedArgumentCompletion.kt @@ -30,7 +30,6 @@ import org.jetbrains.kotlin.psi.KtCallElement import org.jetbrains.kotlin.psi.KtSimpleNameExpression import org.jetbrains.kotlin.psi.KtValueArgument import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType -import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.renderer.render import org.jetbrains.kotlin.types.KotlinType import java.util.* @@ -61,7 +60,7 @@ object NamedArgumentCompletion { for ((name, types) in nameToParameterType) { val typeText = types.singleOrNull()?.let { BasicLookupElementFactory.SHORT_NAMES_RENDERER.renderType(it) } ?: "..." val nameString = name.asString() - val lookupElement = LookupElementBuilder.create(nameString) + val lookupElement = LookupElementBuilder.create("$nameString =") .withPresentableText("$nameString =") .withTailText(" $typeText") .withIcon(KotlinIcons.PARAMETER) diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/Weighers.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/Weighers.kt index 74023b41fb9..4e90a8f314f 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/Weighers.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/Weighers.kt @@ -276,11 +276,10 @@ class SmartCompletionInBasicWeigher( private val descriptorsToSkip = smartCompletion.descriptorsToSkip private val expectedInfos = smartCompletion.expectedInfos - private fun fullMatchWeight(nameSimilarity: Int) = (3L shl 32) + nameSimilarity + private val PRIORITY_COUNT = SmartCompletionItemPriority.values().size - private fun ifNotNullMatchWeight(nameSimilarity: Int) = (2L shl 32) + nameSimilarity - - private fun smartCompletionItemWeight(nameSimilarity: Int) = (1L shl 32) + nameSimilarity + private fun itemWeight(priority: SmartCompletionItemPriority, nameSimilarity: Int) + = (nameSimilarity.toLong() shl 32) + PRIORITY_COUNT - priority.ordinal private val NAMED_ARGUMENT_WEIGHT = 1L @@ -289,16 +288,13 @@ class SmartCompletionInBasicWeigher( private val DESCRIPTOR_TO_SKIP_WEIGHT = -1L // if descriptor is skipped from smart completion then it's probably irrelevant override fun weigh(element: LookupElement): Long { - if (element.getUserData(KEYWORD_VALUE_MATCHED_KEY) != null) { - return fullMatchWeight(0) - } - if (element.getUserData(NAMED_ARGUMENT_KEY) != null) { return NAMED_ARGUMENT_WEIGHT } - if (element.getUserData(SMART_COMPLETION_ITEM_PRIORITY_KEY) != null) { // it's an "additional item" came from smart completion, don't match it against expected type - return smartCompletionItemWeight(element.getUserData(NAME_SIMILARITY_KEY) ?: 0) + val priority = element.getUserData(SMART_COMPLETION_ITEM_PRIORITY_KEY) + if (priority != null) { // it's an "additional item" came from smart completion, don't match it against expected type + return itemWeight(priority, element.getUserData(NAME_SIMILARITY_KEY) ?: 0) } val o = element.`object` @@ -334,9 +330,9 @@ class SmartCompletionInBasicWeigher( } return if (matched.any { it.second.isMatch() }) - fullMatchWeight(nameSimilarity) + itemWeight(SmartCompletionItemPriority.DEFAULT, nameSimilarity) else - ifNotNullMatchWeight(nameSimilarity) + itemWeight(SmartCompletionItemPriority.NULLABLE, nameSimilarity) } } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/GenerateLambda.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/GenerateLambda.kt deleted file mode 100644 index 9dd0df53fa4..00000000000 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/GenerateLambda.kt +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright 2010-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.kotlin.idea.completion.handlers - -import com.intellij.codeInsight.completion.InsertionContext -import com.intellij.codeInsight.lookup.LookupElement -import com.intellij.codeInsight.lookup.LookupElementBuilder -import com.intellij.codeInsight.template.* -import com.intellij.openapi.command.CommandProcessor -import com.intellij.openapi.project.Project -import com.intellij.openapi.util.TextRange -import com.intellij.psi.PsiDocumentManager -import com.intellij.psi.util.PsiTreeUtil -import org.jetbrains.kotlin.builtins.extractParameterNameFromFunctionTypeArgument -import org.jetbrains.kotlin.builtins.getValueParameterTypesFromFunctionType -import org.jetbrains.kotlin.builtins.isFunctionType -import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade -import org.jetbrains.kotlin.idea.core.ExpectedInfos -import org.jetbrains.kotlin.idea.core.KotlinNameSuggester -import org.jetbrains.kotlin.idea.core.fuzzyType -import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers -import org.jetbrains.kotlin.idea.util.application.executeWriteCommand -import org.jetbrains.kotlin.psi.KtExpression -import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.renderer.render -import org.jetbrains.kotlin.resolve.calls.util.getValueParametersCountFromFunctionType -import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode -import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.TypeProjection - -fun insertLambdaTemplate(context: InsertionContext, placeholderRange: TextRange, lambdaType: KotlinType) { - val explicitParameterTypes = needExplicitParameterTypes(context, placeholderRange, lambdaType) - - // we start template later to not interfere with insertion of tail type - val commandProcessor = CommandProcessor.getInstance() - val commandName = commandProcessor.currentCommandName!! - val commandGroupId = commandProcessor.currentCommandGroupId - - val rangeMarker = context.document.createRangeMarker(placeholderRange) - - context.setLaterRunnable { - context.project.executeWriteCommand(commandName, groupId = commandGroupId) { - try { - if (rangeMarker.isValid) { - context.document.deleteString(rangeMarker.startOffset, rangeMarker.endOffset) - context.editor.caretModel.moveToOffset(rangeMarker.startOffset) - val template = buildTemplate(lambdaType, explicitParameterTypes, context.project) - TemplateManager.getInstance(context.project).startTemplate(context.editor, template) - } - } - finally { - rangeMarker.dispose() - } - } - } -} - -fun lambdaPresentation(lambdaType: KotlinType?): String { - if (lambdaType == null) return "{...}" - val parameterTypes = functionParameterTypes(lambdaType) - val parametersPresentation = parameterTypes - .map { - it.extractParameterNameFromFunctionTypeArgument() ?: IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(it) - } - .joinToString(", ") - return "{ $parametersPresentation -> ... }" -} - -private fun needExplicitParameterTypes(context: InsertionContext, placeholderRange: TextRange, lambdaType: KotlinType): Boolean { - PsiDocumentManager.getInstance(context.project).commitAllDocuments() - val file = context.file as KtFile - val expression = PsiTreeUtil.findElementOfClassAtRange(file, placeholderRange.startOffset, placeholderRange.endOffset, KtExpression::class.java) - ?: return false - - val resolutionFacade = file.getResolutionFacade() - val bindingContext = resolutionFacade.analyze(expression, BodyResolveMode.PARTIAL) - val expectedInfos = ExpectedInfos(bindingContext, resolutionFacade, indicesHelper = null, useHeuristicSignatures = false).calculate(expression) - - val functionTypes = expectedInfos - .mapNotNull { it.fuzzyType?.type } - .filter(KotlinType::isFunctionType) - .toSet() - if (functionTypes.size <= 1) return false - - val lambdaParameterCount = getValueParametersCountFromFunctionType(lambdaType) - return functionTypes.filter { getValueParametersCountFromFunctionType(it) == lambdaParameterCount }.size > 1 -} - -private fun buildTemplate(lambdaType: KotlinType, explicitParameterTypes: Boolean, project: Project): Template { - val parameterTypes = functionParameterTypes(lambdaType) - - val manager = TemplateManager.getInstance(project) - - val template = manager.createTemplate("", "") - template.isToShortenLongNames = true - //template.setToReformat(true) //TODO - template.addTextSegment("{ ") - - for ((i, parameterType) in parameterTypes.withIndex()) { - if (i > 0) { - template.addTextSegment(", ") - } - //TODO: check for names in scope - val parameterName = parameterType.extractParameterNameFromFunctionTypeArgument()?.render() - val nameExpression = if (parameterName != null) { - object : Expression() { - override fun calculateResult(context: ExpressionContext?) = TextResult(parameterName) - override fun calculateQuickResult(context: ExpressionContext?): Result? = TextResult(parameterName) - override fun calculateLookupItems(context: ExpressionContext?) = emptyArray() - } - } - else { - val nameSuggestions = KotlinNameSuggester.suggestNamesByType(parameterType, { true }, "p").toTypedArray() - object : Expression() { - override fun calculateResult(context: ExpressionContext?) = TextResult(nameSuggestions[0]) - override fun calculateQuickResult(context: ExpressionContext?): Result? = null - override fun calculateLookupItems(context: ExpressionContext?) - = nameSuggestions.map { LookupElementBuilder.create(it) }.toTypedArray() - } - } - template.addVariable(nameExpression, true) - - if (explicitParameterTypes) { - template.addTextSegment(": " + IdeDescriptorRenderers.SOURCE_CODE.renderType(parameterType)) - } - } - - template.addTextSegment(" -> ") - template.addEndVariable() - template.addTextSegment(" }") - return template -} - -private fun functionParameterTypes(functionType: KotlinType): List { - return functionType.getValueParameterTypesFromFunctionType().map(TypeProjection::getType) -} diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinFunctionInsertHandler.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinFunctionInsertHandler.kt index 738b53c7823..825fdeac35f 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinFunctionInsertHandler.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinFunctionInsertHandler.kt @@ -25,9 +25,11 @@ import com.intellij.openapi.util.TextRange import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiElement import com.intellij.psi.codeStyle.CodeStyleSettingsManager +import org.jetbrains.kotlin.idea.completion.LambdaSignatureTemplates import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings import org.jetbrains.kotlin.idea.util.CallType import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtTypeArgumentList import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.types.KotlinType @@ -157,7 +159,9 @@ sealed class KotlinFunctionInsertHandler(callType: CallType<*>) : KotlinCallable } if (insertLambda && lambdaInfo!!.explicitParameters) { - insertLambdaTemplate(context, TextRange(openingBracketOffset, closeBracketOffset!! + 1), lambdaInfo.lambdaType) + val placeholderRange = TextRange(openingBracketOffset, closeBracketOffset!! + 1) + val explicitParameterTypes = LambdaSignatureTemplates.explicitParameterTypesRequired(context.file as KtFile, placeholderRange, lambdaInfo.lambdaType) + LambdaSignatureTemplates.insertTemplate(context, placeholderRange, lambdaInfo.lambdaType, explicitParameterTypes, signatureOnly = false) return } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/LambdaItems.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/LambdaItems.kt index e518a9b9952..aac64772007 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/LambdaItems.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/LambdaItems.kt @@ -19,12 +19,12 @@ package org.jetbrains.kotlin.idea.completion.smart import com.intellij.codeInsight.lookup.LookupElement import com.intellij.codeInsight.lookup.LookupElementBuilder import com.intellij.openapi.util.TextRange -import org.jetbrains.kotlin.idea.completion.handlers.insertLambdaTemplate -import org.jetbrains.kotlin.idea.completion.handlers.lambdaPresentation +import org.jetbrains.kotlin.idea.completion.LambdaSignatureTemplates import org.jetbrains.kotlin.idea.completion.suppressAutoInsertion import org.jetbrains.kotlin.idea.core.ExpectedInfo import org.jetbrains.kotlin.idea.core.fuzzyType import org.jetbrains.kotlin.resolve.calls.util.getValueParametersCountFromFunctionType +import org.jetbrains.kotlin.types.KotlinType import java.util.* object LambdaItems { @@ -38,15 +38,15 @@ object LambdaItems { val functionExpectedInfos = expectedInfos.filterFunctionExpected() if (functionExpectedInfos.isEmpty()) return - val distinctTypes = functionExpectedInfos + val functionTypes = functionExpectedInfos .mapNotNull { it.fuzzyType?.type } .toSet() - val singleType = if (distinctTypes.size == 1) distinctTypes.single() else null + val singleType = if (functionTypes.size == 1) functionTypes.single() else null val singleSignatureLength = singleType?.let(::getValueParametersCountFromFunctionType) val offerNoParametersLambda = singleSignatureLength == 0 || singleSignatureLength == 1 if (offerNoParametersLambda) { - val lookupElement = LookupElementBuilder.create(lambdaPresentation(null)) + val lookupElement = LookupElementBuilder.create(LambdaSignatureTemplates.DEFAULT_LAMBDA_PRESENTATION) .withInsertHandler(ArtificialElementInsertHandler("{ ", " }", false)) .suppressAutoInsertion() .assignSmartCompletionPriority(SmartCompletionItemPriority.LAMBDA_NO_PARAMS) @@ -55,20 +55,52 @@ object LambdaItems { } if (singleSignatureLength != 0) { - for (functionType in distinctTypes) { - val lookupString = lambdaPresentation(functionType) - val lookupElement = LookupElementBuilder.create(lookupString) - .withInsertHandler({ context, _ -> - val offset = context.startOffset - val placeholder = "{}" - context.document.replaceString(offset, context.tailOffset, placeholder) - insertLambdaTemplate(context, TextRange(offset, offset + placeholder.length), functionType) - }) - .suppressAutoInsertion() - .assignSmartCompletionPriority(SmartCompletionItemPriority.LAMBDA) - .addTailAndNameSimilarity(functionExpectedInfos.filter { it.fuzzyType?.type == functionType }) - collection.add(lookupElement) + for (functionType in functionTypes) { + if (LambdaSignatureTemplates.explicitParameterTypesRequired(functionTypes, functionType)) { + collection.add(createLookupElement( + functionType, + functionExpectedInfos, + LambdaSignatureTemplates.SignaturePresentation.NAMES_OR_TYPES, + explicitParameterTypes = true + )) + + } + else { + collection.add(createLookupElement( + functionType, + functionExpectedInfos, + LambdaSignatureTemplates.SignaturePresentation.NAMES_AND_TYPES, + explicitParameterTypes = true + )) + collection.add(createLookupElement( + functionType, + functionExpectedInfos, + LambdaSignatureTemplates.SignaturePresentation.NAMES, + explicitParameterTypes = false + )) + } } } } + + private fun createLookupElement( + functionType: KotlinType, + functionExpectedInfos: List, + signaturePresentation: LambdaSignatureTemplates.SignaturePresentation, + explicitParameterTypes: Boolean + ): LookupElement { + val lookupString = LambdaSignatureTemplates.lambdaPresentation(functionType, signaturePresentation) + val lookupElement = LookupElementBuilder.create(lookupString) + .withInsertHandler({ context, lookupElement -> + val offset = context.startOffset + val placeholder = "{}" + context.document.replaceString(offset, context.tailOffset, placeholder) + val placeholderRange = TextRange(offset, offset + placeholder.length) + LambdaSignatureTemplates.insertTemplate(context, placeholderRange, functionType, explicitParameterTypes, signatureOnly = false) + }) + .suppressAutoInsertion() + .assignSmartCompletionPriority(SmartCompletionItemPriority.LAMBDA) + .addTailAndNameSimilarity(functionExpectedInfos.filter { it.fuzzyType?.type == functionType }) + return lookupElement + } } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/LambdaSignatureItems.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/LambdaSignatureItems.kt new file mode 100644 index 00000000000..89b34dd2dd8 --- /dev/null +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/LambdaSignatureItems.kt @@ -0,0 +1,87 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.idea.completion.smart + +import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.codeInsight.lookup.LookupElementBuilder +import com.intellij.openapi.util.TextRange +import org.jetbrains.kotlin.builtins.getValueParameterTypesFromFunctionType +import org.jetbrains.kotlin.builtins.isFunctionType +import org.jetbrains.kotlin.idea.completion.LambdaSignatureTemplates +import org.jetbrains.kotlin.idea.completion.suppressAutoInsertion +import org.jetbrains.kotlin.idea.core.ExpectedInfos +import org.jetbrains.kotlin.idea.core.fuzzyType +import org.jetbrains.kotlin.idea.resolve.ResolutionFacade +import org.jetbrains.kotlin.psi.KtBlockExpression +import org.jetbrains.kotlin.psi.KtExpression +import org.jetbrains.kotlin.psi.KtFunctionLiteral +import org.jetbrains.kotlin.psi.KtLambdaExpression +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.types.KotlinType + +object LambdaSignatureItems { + fun addToCollection( + collection: MutableCollection, + position: KtExpression, + bindingContext: BindingContext, + resolutionFacade: ResolutionFacade + ) { + val block = position.parent as? KtBlockExpression ?: return + if (position != block.statements.first()) return + val functionLiteral = block.parent as? KtFunctionLiteral ?: return + if (functionLiteral.arrow != null) return + val literalExpression = functionLiteral.parent as KtLambdaExpression + + val expectedFunctionTypes = ExpectedInfos(bindingContext, resolutionFacade, null).calculate(literalExpression) + .mapNotNull { it.fuzzyType?.type } + .filter { it.isFunctionType } + .toSet() + for (functionType in expectedFunctionTypes) { + if (functionType.getValueParameterTypesFromFunctionType().isEmpty()) continue + + if (LambdaSignatureTemplates.explicitParameterTypesRequired(expectedFunctionTypes, functionType)) { + collection.add(createLookupElement(functionType, LambdaSignatureTemplates.SignaturePresentation.NAMES_OR_TYPES, explicitParameterTypes = true)) + } + else { + collection.add(createLookupElement(functionType, LambdaSignatureTemplates.SignaturePresentation.NAMES, explicitParameterTypes = false)) + collection.add(createLookupElement(functionType, LambdaSignatureTemplates.SignaturePresentation.NAMES_AND_TYPES, explicitParameterTypes = true)) + } + } + } + + private fun createLookupElement( + functionType: KotlinType, + signaturePresentation: LambdaSignatureTemplates.SignaturePresentation, + explicitParameterTypes: Boolean + ): LookupElement { + val lookupString = LambdaSignatureTemplates.signaturePresentation(functionType, signaturePresentation) + val priority = if (explicitParameterTypes) + SmartCompletionItemPriority.LAMBDA_SIGNATURE_EXPLICIT_PARAMETER_TYPES + else + SmartCompletionItemPriority.LAMBDA_SIGNATURE + val lookupElement = LookupElementBuilder.create(lookupString) + .withInsertHandler({ context, lookupElement -> + val offset = context.startOffset + val placeholder = "{}" + context.document.replaceString(offset, context.tailOffset, placeholder) + LambdaSignatureTemplates.insertTemplate(context, TextRange(offset, offset + placeholder.length), functionType, explicitParameterTypes, signatureOnly = true) + }) + .suppressAutoInsertion() + .assignSmartCompletionPriority(priority) + return lookupElement + } +} \ No newline at end of file diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletion.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletion.kt index 4554192683f..d0ee3bf80f4 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletion.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletion.kt @@ -220,6 +220,8 @@ class SmartCompletion( items.addNamedArgumentsWithLiteralValueItems(expectedInfos) + LambdaSignatureItems.addToCollection(items, expressionWithType, bindingContext, resolutionFacade) + if (!forBasicCompletion) { LambdaItems.addToCollection(items, expectedInfos) diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/Utils.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/Utils.kt index 7aef2194700..d6ce625bd60 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/Utils.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/Utils.kt @@ -262,6 +262,8 @@ fun CallableDescriptor.callableReferenceType(resolutionFacade: ResolutionFacade, enum class SmartCompletionItemPriority { MULTIPLE_ARGUMENTS_ITEM, + LAMBDA_SIGNATURE, + LAMBDA_SIGNATURE_EXPLICIT_PARAMETER_TYPES, IT, TRUE, FALSE, diff --git a/idea/idea-completion/testData/basic/common/namedArguments/AfterBrace.kt b/idea/idea-completion/testData/basic/common/namedArguments/AfterBrace.kt index e83610a629a..ea13c7f99c2 100644 --- a/idea/idea-completion/testData/basic/common/namedArguments/AfterBrace.kt +++ b/idea/idea-completion/testData/basic/common/namedArguments/AfterBrace.kt @@ -3,4 +3,4 @@ fun small(param: Int) { fun test() = small() -// EXIST: {"lookupString":"param","tailText":" Int","itemText":"param ="} \ No newline at end of file +// EXIST: {"lookupString":"param =","tailText":" Int","itemText":"param ="} \ No newline at end of file diff --git a/idea/idea-completion/testData/basic/common/namedArguments/AfterComma.kt b/idea/idea-completion/testData/basic/common/namedArguments/AfterComma.kt index ef6a1123010..d75ce1ed4dc 100644 --- a/idea/idea-completion/testData/basic/common/namedArguments/AfterComma.kt +++ b/idea/idea-completion/testData/basic/common/namedArguments/AfterComma.kt @@ -4,4 +4,4 @@ fun small(first: Int, second: Int) { fun test() = small(12, ) // ABSENT: first -// EXIST: { lookupString:"second", itemText:"second =" } +// EXIST: { lookupString:"second =", itemText:"second =" } diff --git a/idea/idea-completion/testData/basic/common/namedArguments/AfterVararg.kt b/idea/idea-completion/testData/basic/common/namedArguments/AfterVararg.kt index 9256c01bae4..a2ec21567a0 100644 --- a/idea/idea-completion/testData/basic/common/namedArguments/AfterVararg.kt +++ b/idea/idea-completion/testData/basic/common/namedArguments/AfterVararg.kt @@ -4,4 +4,4 @@ fun bar(s: String){ foo("", "", ) } -// EXIST: { lookupString:"option", itemText:"option =" } +// EXIST: { lookupString:"option =", itemText:"option =" } diff --git a/idea/idea-completion/testData/basic/common/namedArguments/CompactTypeNames.kt b/idea/idea-completion/testData/basic/common/namedArguments/CompactTypeNames.kt index 2a0d391ec0e..1be94010343 100644 --- a/idea/idea-completion/testData/basic/common/namedArguments/CompactTypeNames.kt +++ b/idea/idea-completion/testData/basic/common/namedArguments/CompactTypeNames.kt @@ -5,5 +5,5 @@ fun small(paramFirst: Sequence, paramSecond: Comparable) -// EXIST: {"lookupString":"paramSecond","tailText":" Comparable>","itemText":"paramSecond ="} -// EXIST: {"lookupString":"paramFirst","tailText":" Sequence","itemText":"paramFirst ="} +// EXIST: {"lookupString":"paramSecond =","tailText":" Comparable>","itemText":"paramSecond ="} +// EXIST: {"lookupString":"paramFirst =","tailText":" Sequence","itemText":"paramFirst ="} diff --git a/idea/idea-completion/testData/basic/common/namedArguments/InParameterExpression.kt b/idea/idea-completion/testData/basic/common/namedArguments/InParameterExpression.kt index 74d4dbc04d7..643ef3cb3f5 100644 --- a/idea/idea-completion/testData/basic/common/namedArguments/InParameterExpression.kt +++ b/idea/idea-completion/testData/basic/common/namedArguments/InParameterExpression.kt @@ -6,6 +6,6 @@ fun small(paramFirst: Int, paramSecond: Int) { fun test() = small(paramFirst = param) // EXIST: paramTest -// ABSENT: {"lookupString":"paramFirst","tailText":" Int","itemText":"paramFirst ="} -// ABSENT: paramSecond +// ABSENT: { itemText: "paramFirst =" } +// ABSENT: { itemText: "paramSecond =" } // NOTHING_ELSE diff --git a/idea/idea-completion/testData/basic/common/namedArguments/NamedArgumentsFromOverloads.kt b/idea/idea-completion/testData/basic/common/namedArguments/NamedArgumentsFromOverloads.kt index 1ca470ef68a..379de057e88 100644 --- a/idea/idea-completion/testData/basic/common/namedArguments/NamedArgumentsFromOverloads.kt +++ b/idea/idea-completion/testData/basic/common/namedArguments/NamedArgumentsFromOverloads.kt @@ -11,7 +11,7 @@ fun other() { } // EXIST: nLocal -// EXIST: { lookupString:"nFirst", itemText:"nFirst =", tailText: " String" } +// EXIST: { lookupString:"nFirst =", itemText:"nFirst =", tailText: " String" } // EXIST: { itemText: "nClassParam =", tailText: " String" } // EXIST: { itemText: "nClassField =", tailText: " String" } // EXIST: { itemText: "nSecond =", tailText: " String?" } diff --git a/idea/idea-completion/testData/basic/common/namedArguments/NoAlreadyUsedParameters.kt b/idea/idea-completion/testData/basic/common/namedArguments/NoAlreadyUsedParameters.kt index d1fce8ccd54..91ab373cc44 100644 --- a/idea/idea-completion/testData/basic/common/namedArguments/NoAlreadyUsedParameters.kt +++ b/idea/idea-completion/testData/basic/common/namedArguments/NoAlreadyUsedParameters.kt @@ -4,8 +4,8 @@ fun test() { foo("str", paramThird = "test", param) } -// ABSENT: paramFirst -// EXIST: paramSecond -// ABSENT: paramThird -// EXIST: paramFourth +// ABSENT: "paramFirst =" +// EXIST: "paramSecond =" +// ABSENT: "paramThird =" +// EXIST: "paramFourth =" diff --git a/idea/idea-completion/testData/basic/common/namedArguments/NoParamsFromUnapplicableOverload.kt b/idea/idea-completion/testData/basic/common/namedArguments/NoParamsFromUnapplicableOverload.kt index 5ea14fde416..d6cea25c235 100644 --- a/idea/idea-completion/testData/basic/common/namedArguments/NoParamsFromUnapplicableOverload.kt +++ b/idea/idea-completion/testData/basic/common/namedArguments/NoParamsFromUnapplicableOverload.kt @@ -5,7 +5,7 @@ fun test() { foo(12, param) } -// ABSENT: paramFirst -// EXIST: {"lookupString":"paramSecond","tailText":" Int","itemText":"paramSecond ="} -// ABSENT: paramThird -// ABSENT: paramFourth \ No newline at end of file +// ABSENT: "paramFirst =" +// EXIST: {"lookupString":"paramSecond =","tailText":" Int","itemText":"paramSecond ="} +// ABSENT: "paramThird =" +// ABSENT: "paramFourth =" \ No newline at end of file diff --git a/idea/idea-completion/testData/basic/common/namedArguments/NotOnlyNamedArguments.kt b/idea/idea-completion/testData/basic/common/namedArguments/NotOnlyNamedArguments.kt index 7fb4c496401..7d4c5506245 100644 --- a/idea/idea-completion/testData/basic/common/namedArguments/NotOnlyNamedArguments.kt +++ b/idea/idea-completion/testData/basic/common/namedArguments/NotOnlyNamedArguments.kt @@ -4,6 +4,6 @@ fun foo(first: Int, second: Int, third: String) { fun test(p: Int) = foo(12, , third = "") // EXIST: p -// ABSENT: first -// EXIST: third -// EXIST: second +// ABSENT: "first =" +// EXIST: "third =" +// EXIST: "second =" diff --git a/idea/idea-completion/testData/basic/common/namedArguments/NotOnlyNamedArguments2.kt b/idea/idea-completion/testData/basic/common/namedArguments/NotOnlyNamedArguments2.kt index a5089cd1bad..34e2cecdbf4 100644 --- a/idea/idea-completion/testData/basic/common/namedArguments/NotOnlyNamedArguments2.kt +++ b/idea/idea-completion/testData/basic/common/namedArguments/NotOnlyNamedArguments2.kt @@ -4,6 +4,6 @@ fun foo(first: Int, second: Int, third: String) { fun test(p: Int) = foo(second = 3) // EXIST: p -// EXIST: first -// EXIST: second -// EXIST: third +// EXIST: "first =" +// EXIST: "second =" +// EXIST: "third =" diff --git a/idea/idea-completion/testData/basic/common/namedArguments/OfConstructor.kt b/idea/idea-completion/testData/basic/common/namedArguments/OfConstructor.kt index 80932f3655c..1157af6638f 100644 --- a/idea/idea-completion/testData/basic/common/namedArguments/OfConstructor.kt +++ b/idea/idea-completion/testData/basic/common/namedArguments/OfConstructor.kt @@ -6,5 +6,5 @@ fun other() { Foo(p) } -// EXIST: {"lookupString":"pFirst","tailText":" String?","itemText":"pFirst ="} -// EXIST: {"lookupString":"pSecond","tailText":" Int","itemText":"pSecond ="} \ No newline at end of file +// EXIST: {"lookupString":"pFirst =","tailText":" String?","itemText":"pFirst ="} +// EXIST: {"lookupString":"pSecond =","tailText":" Int","itemText":"pSecond ="} \ No newline at end of file diff --git a/idea/idea-completion/testData/basic/common/namedArguments/OnlyNamedArguments.kt b/idea/idea-completion/testData/basic/common/namedArguments/OnlyNamedArguments.kt index 3b9457c582b..8c2d40aed2e 100644 --- a/idea/idea-completion/testData/basic/common/namedArguments/OnlyNamedArguments.kt +++ b/idea/idea-completion/testData/basic/common/namedArguments/OnlyNamedArguments.kt @@ -4,7 +4,7 @@ fun foo(first: Int, second: Int, third: String) { fun test(p: Int) = foo(12, third = "", ) // ABSENT: p -// ABSENT: first -// ABSENT: third -// EXIST: second +// ABSENT: "first =" +// ABSENT: "third =" +// EXIST: "second =" // NOTHING_ELSE diff --git a/idea/idea-completion/testData/basic/common/namedArguments/WithParameterExpression.kt b/idea/idea-completion/testData/basic/common/namedArguments/WithParameterExpression.kt index 598a98981d6..634cee304b8 100644 --- a/idea/idea-completion/testData/basic/common/namedArguments/WithParameterExpression.kt +++ b/idea/idea-completion/testData/basic/common/namedArguments/WithParameterExpression.kt @@ -5,8 +5,8 @@ fun small(paramFirst: Int, paramSecond: Int) { fun test() = small(paramFirst = 12) -// EXIST: paramFirst -// EXIST: paramSecond +// EXIST: "paramFirst =" +// EXIST: "paramSecond =" // EXIST: paramTest // NOTHING_ELSE diff --git a/idea/idea-completion/testData/basic/withLib/NamedArgumentsKotlin.kt b/idea/idea-completion/testData/basic/withLib/NamedArgumentsKotlin.kt index 7fc313d3a2b..d061384493a 100644 --- a/idea/idea-completion/testData/basic/withLib/NamedArgumentsKotlin.kt +++ b/idea/idea-completion/testData/basic/withLib/NamedArgumentsKotlin.kt @@ -3,4 +3,4 @@ import lib.KotlinClass fun test() = KotlinClass().foo() // ABSENT: p0 -// EXIST: { lookupString:"paramName", itemText:"paramName =" } +// EXIST: { lookupString:"paramName =", itemText:"paramName =" } diff --git a/idea/idea-completion/testData/handlers/NamedParametersCompletionOnEqual.kt.after b/idea/idea-completion/testData/handlers/NamedParametersCompletionOnEqual.kt.after index 33eaf1b2c4e..0793912819d 100644 --- a/idea/idea-completion/testData/handlers/NamedParametersCompletionOnEqual.kt.after +++ b/idea/idea-completion/testData/handlers/NamedParametersCompletionOnEqual.kt.after @@ -4,5 +4,5 @@ fun paramFun() {} fun test() { // Type '=', completion should be finishied - foo(paramTest = ) + foo(paramTest =) } diff --git a/idea/idea-completion/testData/handlers/charFilter/NamedParameter1.kt b/idea/idea-completion/testData/handlers/charFilter/NamedParameter1.kt index 4c4b4ddb05c..89f2426f116 100644 --- a/idea/idea-completion/testData/handlers/charFilter/NamedParameter1.kt +++ b/idea/idea-completion/testData/handlers/charFilter/NamedParameter1.kt @@ -4,5 +4,5 @@ fun test() { foo(xxx = 10, ) } -// ELEMENT: yyy +// ELEMENT: "yyy =" // CHAR: = diff --git a/idea/idea-completion/testData/handlers/charFilter/NamedParameter1.kt.after b/idea/idea-completion/testData/handlers/charFilter/NamedParameter1.kt.after index 57d46120ddb..dcda4977c08 100644 --- a/idea/idea-completion/testData/handlers/charFilter/NamedParameter1.kt.after +++ b/idea/idea-completion/testData/handlers/charFilter/NamedParameter1.kt.after @@ -1,8 +1,8 @@ fun foo(xxx: Int, yyy: Int) fun test() { - foo(xxx = 10, yyy = ) + foo(xxx = 10, yyy =) } -// ELEMENT: yyy +// ELEMENT: "yyy =" // CHAR: = diff --git a/idea/idea-completion/testData/handlers/charFilter/NamedParameter2.kt b/idea/idea-completion/testData/handlers/charFilter/NamedParameter2.kt index d73bf3fbca6..ff2ed0221f1 100644 --- a/idea/idea-completion/testData/handlers/charFilter/NamedParameter2.kt +++ b/idea/idea-completion/testData/handlers/charFilter/NamedParameter2.kt @@ -4,5 +4,5 @@ fun test() { foo(xxx = 10, ) } -// ELEMENT: yyy +// ELEMENT: "yyy =" // CHAR: ' ' diff --git a/idea/idea-completion/testData/handlers/charFilter/NamedParameter2.kt.after b/idea/idea-completion/testData/handlers/charFilter/NamedParameter2.kt.after index 56fd63c7079..f60df245b9b 100644 --- a/idea/idea-completion/testData/handlers/charFilter/NamedParameter2.kt.after +++ b/idea/idea-completion/testData/handlers/charFilter/NamedParameter2.kt.after @@ -1,8 +1,8 @@ fun foo(xxx: Int, yyy: Int) fun test() { - foo(xxx = 10, yyy = ) + foo(xxx = 10, yyy ) } -// ELEMENT: yyy +// ELEMENT: "yyy =" // CHAR: ' ' diff --git a/idea/idea-completion/testData/handlers/smart/lambda/3.kt b/idea/idea-completion/testData/handlers/smart/lambda/3.kt index 050a21c3fe7..d7606bc2e1b 100644 --- a/idea/idea-completion/testData/handlers/smart/lambda/3.kt +++ b/idea/idea-completion/testData/handlers/smart/lambda/3.kt @@ -4,4 +4,4 @@ fun bar() { foo() } -// ELEMENT: "{ Int -> ... }" +// ELEMENT: "{ i -> ... }" diff --git a/idea/idea-completion/testData/handlers/smart/lambda/3.kt.after b/idea/idea-completion/testData/handlers/smart/lambda/3.kt.after index 33737097103..288119138ce 100644 --- a/idea/idea-completion/testData/handlers/smart/lambda/3.kt.after +++ b/idea/idea-completion/testData/handlers/smart/lambda/3.kt.after @@ -4,4 +4,4 @@ fun bar() { foo({ i -> }) } -// ELEMENT: "{ Int -> ... }" +// ELEMENT: "{ i -> ... }" diff --git a/idea/idea-completion/testData/handlers/smart/lambda/4.kt b/idea/idea-completion/testData/handlers/smart/lambda/4.kt index 9b9adce74b6..4c8181f06f0 100644 --- a/idea/idea-completion/testData/handlers/smart/lambda/4.kt +++ b/idea/idea-completion/testData/handlers/smart/lambda/4.kt @@ -5,4 +5,4 @@ fun bar() { foo() } -// ELEMENT: "{ String, StringBuilder -> ... }" +// ELEMENT: "{ s, stringBuilder -> ... }" diff --git a/idea/idea-completion/testData/handlers/smart/lambda/4.kt.after b/idea/idea-completion/testData/handlers/smart/lambda/4.kt.after index 1013fdbd882..d62c7b0f2b8 100644 --- a/idea/idea-completion/testData/handlers/smart/lambda/4.kt.after +++ b/idea/idea-completion/testData/handlers/smart/lambda/4.kt.after @@ -5,4 +5,4 @@ fun bar() { foo({ s, stringBuilder -> }) } -// ELEMENT: "{ String, StringBuilder -> ... }" +// ELEMENT: "{ s, stringBuilder -> ... }" diff --git a/idea/idea-completion/testData/smart/AfterEmptyArgument.kt b/idea/idea-completion/testData/smart/AfterEmptyArgument.kt index b450a5c14ee..b871ecd91f9 100644 --- a/idea/idea-completion/testData/smart/AfterEmptyArgument.kt +++ b/idea/idea-completion/testData/smart/AfterEmptyArgument.kt @@ -4,7 +4,7 @@ fun bar(pInt: Int, pString: String) { foo(param2 = , ) } -// EXIST: { lookupString: "param1", itemText: "param1 =" } -// EXIST: { lookupString: "param3", itemText: "param3 =" } +// EXIST: { lookupString: "param1 =", itemText: "param1 =" } +// EXIST: { lookupString: "param3 =", itemText: "param3 =" } // ABSENT: param2 // NOTHING_ELSE diff --git a/idea/idea-completion/testData/smart/AfterNamedArgument.kt b/idea/idea-completion/testData/smart/AfterNamedArgument.kt index 6fff0fbf8ab..e9260d50974 100644 --- a/idea/idea-completion/testData/smart/AfterNamedArgument.kt +++ b/idea/idea-completion/testData/smart/AfterNamedArgument.kt @@ -4,7 +4,7 @@ fun bar(pInt: Int, pString: String) { foo(param2 = 1, ) } -// EXIST: { lookupString: "param1", itemText: "param1 =" } -// EXIST: { lookupString: "param3", itemText: "param3 =" } +// EXIST: { lookupString: "param1 =", itemText: "param1 =" } +// EXIST: { lookupString: "param3 =", itemText: "param3 =" } // ABSENT: param2 // NOTHING_ELSE diff --git a/idea/idea-completion/testData/smart/functionLiterals/2.kt b/idea/idea-completion/testData/smart/functionLiterals/2.kt index 6a525628f6d..a68c229e796 100644 --- a/idea/idea-completion/testData/smart/functionLiterals/2.kt +++ b/idea/idea-completion/testData/smart/functionLiterals/2.kt @@ -4,5 +4,7 @@ fun bar() { foo() } +// WITH_ORDER // EXIST: "{...}" -// EXIST: "{ String -> ... }" +// EXIST: "{ s -> ... }" +// EXIST: "{ s: String -> ... }" diff --git a/idea/idea-completion/testData/smart/functionLiterals/3.kt b/idea/idea-completion/testData/smart/functionLiterals/3.kt index 2daa8dcf538..57cfae0e7d9 100644 --- a/idea/idea-completion/testData/smart/functionLiterals/3.kt +++ b/idea/idea-completion/testData/smart/functionLiterals/3.kt @@ -4,5 +4,7 @@ fun bar() { foo() } +// WITH_ORDER // ABSENT: "{...}" -// EXIST: "{ String, Int -> ... }" +// EXIST: "{ s, i -> ... }" +// EXIST: "{ s: String, i: Int -> ... }" diff --git a/idea/idea-completion/testData/smart/functionLiterals/5.kt b/idea/idea-completion/testData/smart/functionLiterals/5.kt index 2c940ce970d..c31b7639ed8 100644 --- a/idea/idea-completion/testData/smart/functionLiterals/5.kt +++ b/idea/idea-completion/testData/smart/functionLiterals/5.kt @@ -4,5 +4,7 @@ fun bar() { foo() } +// WITH_ORDER // EXIST: "{...}" -// EXIST: "{ Int -> ... }" +// EXIST: "{ i -> ... }" +// EXIST: "{ i: Int -> ... }" diff --git a/idea/idea-completion/testData/smart/functionLiterals/ExplicitParameterTypesRequired.kt b/idea/idea-completion/testData/smart/functionLiterals/ExplicitParameterTypesRequired.kt new file mode 100644 index 00000000000..afdb6c94d51 --- /dev/null +++ b/idea/idea-completion/testData/smart/functionLiterals/ExplicitParameterTypesRequired.kt @@ -0,0 +1,11 @@ +fun foo(p: (String, Int) -> Unit){} +fun foo(p: (Char, xx: Any) -> Unit){} + +fun bar() { + foo() +} + +// ABSENT: "{ s, i -> ... }" +// ABSENT: "{ c, xx -> ... }" +// EXIST: "{ String, Int -> ... }" +// EXIST: "{ Char, xx -> ... }" diff --git a/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesis1.kt b/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesis1.kt index cba2b28c971..feabb526917 100644 --- a/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesis1.kt +++ b/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesis1.kt @@ -1,8 +1,10 @@ -fun foo(p: Int, handler: (String, Char) -> Unit){} +fun foo(p: Int, handler: (String, xx: Char) -> Unit){} fun bar(handler: (String, Char) -> Unit) { foo(1) } -// EXIST: "{ String, Char -> ... }" +// WITH_ORDER +// EXIST: "{ s, xx -> ... }" +// EXIST: "{ s: String, xx: Char -> ... }" // ABSENT: handler \ No newline at end of file diff --git a/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesis2.kt b/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesis2.kt index 5642badc861..dbda92ed476 100644 --- a/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesis2.kt +++ b/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesis2.kt @@ -5,5 +5,6 @@ fun bar(p: String.(Int) -> Unit) { } // EXIST: "{...}" -// EXIST: "{ Int -> ... }" +// EXIST: "{ i -> ... }" +// EXIST: "{ i: Int -> ... }" // ABSENT: p diff --git a/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesis3.kt b/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesis3.kt index 95dc7958baf..1e03797b49c 100644 --- a/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesis3.kt +++ b/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesis3.kt @@ -4,5 +4,6 @@ fun bar(handler: (String, Char) -> Unit) { foo } -// EXIST: "{ String, Char -> ... }" +// EXIST: "{ s, c -> ... }" +// EXIST: "{ s: String, c: Char -> ... }" // ABSENT: handler \ No newline at end of file diff --git a/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesis4.kt b/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesis4.kt index 2623157d746..6890392df2c 100644 --- a/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesis4.kt +++ b/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesis4.kt @@ -4,5 +4,6 @@ fun bar(handler: (String, Char) -> Unit) { "".foo } -// EXIST: "{ String, Char -> ... }" +// EXIST: "{ s, c -> ... }" +// EXIST: "{ s: String, c: Char -> ... }" // ABSENT: handler \ No newline at end of file diff --git a/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesis5.kt b/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesis5.kt index 5d134950ed7..84830519805 100644 --- a/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesis5.kt +++ b/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesis5.kt @@ -4,5 +4,6 @@ fun bar(handler: (String, Char) -> Unit) { "" foo } -// EXIST: "{ String, Char -> ... }" +// EXIST: "{ s, c -> ... }" +// EXIST: "{ s: String, c: Char -> ... }" // EXIST: handler \ No newline at end of file diff --git a/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesis6.kt b/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesis6.kt index b4433d56cf7..f141d3033b8 100644 --- a/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesis6.kt +++ b/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesis6.kt @@ -4,6 +4,7 @@ fun bar(handler: (String, Char) -> Unit) { foo(1) } -// EXIST: "{ String, Char -> ... }" +// EXIST: "{ s, c -> ... }" +// EXIST: "{ s: String, c: Char -> ... }" // ABSENT: null // ABSENT: handler \ No newline at end of file diff --git a/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesis7.kt b/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesis7.kt index 36dcae63674..89b68c4699c 100644 --- a/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesis7.kt +++ b/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesis7.kt @@ -4,5 +4,6 @@ fun bar(handler: (String, Char) -> Unit) { foo() } -// EXIST: "{ String, Char -> ... }" +// EXIST: "{ s, c -> ... }" +// EXIST: "{ s: String, c: Char -> ... }" // ABSENT: handler \ No newline at end of file diff --git a/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesis8.kt b/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesis8.kt index eb955b4ca42..43313ae73a7 100644 --- a/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesis8.kt +++ b/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesis8.kt @@ -4,5 +4,6 @@ fun bar(handler: (String, Char) -> Unit) { foo } -// EXIST: "{ String, Char -> ... }" +// EXIST: "{ s, c -> ... }" +// EXIST: "{ s: String, c: Char -> ... }" // ABSENT: handler \ No newline at end of file diff --git a/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesisAndVararg1.kt b/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesisAndVararg1.kt index 4cab0af568d..722bf8ad25f 100644 --- a/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesisAndVararg1.kt +++ b/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesisAndVararg1.kt @@ -4,5 +4,6 @@ fun bar(handler: (String, Char) -> Unit) { foo() } -// EXIST: "{ String, Char -> ... }" +// EXIST: "{ s, c -> ... }" +// EXIST: "{ s: String, c: Char -> ... }" // ABSENT: handler \ No newline at end of file diff --git a/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesisAndVararg2.kt b/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesisAndVararg2.kt index b0601235a8e..bde8d1cda19 100644 --- a/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesisAndVararg2.kt +++ b/idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesisAndVararg2.kt @@ -4,5 +4,6 @@ fun bar(handler: (String, Char) -> Unit) { foo(1, 2) } -// EXIST: "{ String, Char -> ... }" +// EXIST: "{ s, c -> ... }" +// EXIST: "{ s: String, c: Char -> ... }" // ABSENT: handler \ No newline at end of file diff --git a/idea/idea-completion/testData/smart/lambdaSignature/ExplicitParameterTypesRequired.kt b/idea/idea-completion/testData/smart/lambdaSignature/ExplicitParameterTypesRequired.kt new file mode 100644 index 00000000000..2b068b969d5 --- /dev/null +++ b/idea/idea-completion/testData/smart/lambdaSignature/ExplicitParameterTypesRequired.kt @@ -0,0 +1,11 @@ +fun foo(p: (String, Int) -> Unit){} +fun foo(p: (Char, xx: Any) -> Unit){} + +fun bar() { + foo { } +} + +// EXIST: "String, Int ->" +// EXIST: "Char, xx ->" +// ABSENT: "s, i ->" +// ABSENT: "c, xx ->" diff --git a/idea/idea-completion/testData/smart/lambdaSignature/MultipleParameters.kt b/idea/idea-completion/testData/smart/lambdaSignature/MultipleParameters.kt new file mode 100644 index 00000000000..6b5224340f5 --- /dev/null +++ b/idea/idea-completion/testData/smart/lambdaSignature/MultipleParameters.kt @@ -0,0 +1,7 @@ +fun foo(p: Int) { + "abc".fold(1) { } +} + +// EXIST: p +// EXIST: "acc: Int, c: Char ->" +// EXIST: "acc, c ->" diff --git a/idea/idea-completion/testData/smart/lambdaSignature/NotAfterComma.kt b/idea/idea-completion/testData/smart/lambdaSignature/NotAfterComma.kt new file mode 100644 index 00000000000..d5887d6eefe --- /dev/null +++ b/idea/idea-completion/testData/smart/lambdaSignature/NotAfterComma.kt @@ -0,0 +1,5 @@ +fun foo(p: Int) { + "abc".fold(1) { acc, } +} + +// NOTHING_ELSE diff --git a/idea/idea-completion/testData/smart/lambdaSignature/NotInBody.kt b/idea/idea-completion/testData/smart/lambdaSignature/NotInBody.kt new file mode 100644 index 00000000000..63574c563d2 --- /dev/null +++ b/idea/idea-completion/testData/smart/lambdaSignature/NotInBody.kt @@ -0,0 +1,7 @@ +fun foo(p: Int) { + "abc".fold(1) { acc, c -> } +} + +// EXIST: p +// ABSENT: "acc: Int, c: Char ->" +// ABSENT: "acc, c ->" diff --git a/idea/idea-completion/testData/smart/lambdaSignature/SingleParameter.kt b/idea/idea-completion/testData/smart/lambdaSignature/SingleParameter.kt new file mode 100644 index 00000000000..f93906dab76 --- /dev/null +++ b/idea/idea-completion/testData/smart/lambdaSignature/SingleParameter.kt @@ -0,0 +1,7 @@ +fun foo(p: Boolean) { + "abc".filter { } +} + +// EXIST: p +// EXIST: "c ->" +// EXIST: "c: Char ->" diff --git a/idea/idea-completion/testData/weighers/basic/LambdaSignature.kt b/idea/idea-completion/testData/weighers/basic/LambdaSignature.kt new file mode 100644 index 00000000000..f113d8d1573 --- /dev/null +++ b/idea/idea-completion/testData/weighers/basic/LambdaSignature.kt @@ -0,0 +1,8 @@ +fun String.fold(initial: R, operation: (acc: R, Char) -> R): R = TODO() + +fun foo(p: Int) { + "abc".fold(1) { } +} + +// ORDER: "acc, c ->" +// ORDER: "acc: Int, c: Char ->" diff --git a/idea/idea-completion/testData/weighers/basic/NamedParameters.kt b/idea/idea-completion/testData/weighers/basic/NamedParameters.kt index 9000b2f0aad..c37b97fda53 100644 --- a/idea/idea-completion/testData/weighers/basic/NamedParameters.kt +++ b/idea/idea-completion/testData/weighers/basic/NamedParameters.kt @@ -20,6 +20,6 @@ fun test(listParam: Int) { // ORDER: listImportedVal // ORDER: listThisFileFun // ORDER: listImportedFun -// ORDER: listMatch -// ORDER: listNew +// ORDER: "listMatch =" +// ORDER: "listNew =" // ORDER: listFunNotMatchingType diff --git a/idea/idea-completion/testData/weighers/basic/NamedParameters2.kt b/idea/idea-completion/testData/weighers/basic/NamedParameters2.kt index 39de4c51254..a759a0d7b5e 100644 --- a/idea/idea-completion/testData/weighers/basic/NamedParameters2.kt +++ b/idea/idea-completion/testData/weighers/basic/NamedParameters2.kt @@ -6,6 +6,6 @@ fun test(tri: Boolean, trb: Int) { // ORDER: true // ORDER: tri -// ORDER: tra +// ORDER: "tra =" // ORDER: trb // ORDER: try diff --git a/idea/idea-completion/testData/weighers/basic/NamedParameters3.kt b/idea/idea-completion/testData/weighers/basic/NamedParameters3.kt index 3fd27393d30..0b0bd379478 100644 --- a/idea/idea-completion/testData/weighers/basic/NamedParameters3.kt +++ b/idea/idea-completion/testData/weighers/basic/NamedParameters3.kt @@ -11,5 +11,5 @@ fun test(insa: Any) { } // ORDER: instance -// ORDER: insp +// ORDER: "insp =" // ORDER: insa diff --git a/idea/idea-completion/testData/weighers/basic/expectedInfo/MultiArgsItem.kt b/idea/idea-completion/testData/weighers/basic/expectedInfo/MultiArgsItem.kt index 541366687b4..f8fd61fb347 100644 --- a/idea/idea-completion/testData/weighers/basic/expectedInfo/MultiArgsItem.kt +++ b/idea/idea-completion/testData/weighers/basic/expectedInfo/MultiArgsItem.kt @@ -8,5 +8,5 @@ fun bar(b: I2, a: I1, c: I1) { } // ORDER: a -// ORDER: c // ORDER: "a, b, c" +// ORDER: c diff --git a/idea/idea-completion/testData/weighers/smart/CallableReference_NothingLast.kt b/idea/idea-completion/testData/weighers/smart/CallableReference_NothingLast.kt index eafdd408ec0..f95e4e8abb3 100644 --- a/idea/idea-completion/testData/weighers/smart/CallableReference_NothingLast.kt +++ b/idea/idea-completion/testData/weighers/smart/CallableReference_NothingLast.kt @@ -8,5 +8,6 @@ fun f() { } // ORDER: {...} -// ORDER: { Int -> ... } +// ORDER: { i -> ... } +// ORDER: { i: Int -> ... } // ORDER: ::fff2 diff --git a/idea/idea-completion/testData/weighers/smart/FunctionExpected.kt b/idea/idea-completion/testData/weighers/smart/FunctionExpected.kt index 2f9e1e3195e..51d50d8ef1a 100644 --- a/idea/idea-completion/testData/weighers/smart/FunctionExpected.kt +++ b/idea/idea-completion/testData/weighers/smart/FunctionExpected.kt @@ -10,7 +10,8 @@ fun bar(p: (String) -> Boolean) { // ORDER: ::doFilter // ORDER: p // ORDER: {...} -// ORDER: { String -> ... } +// ORDER: { s -> ... } +// ORDER: { s: String -> ... } // ORDER: ::x // ORDER: ::TODO // ORDER: ::error diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmSmartCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmSmartCompletionTestGenerated.java index b6a6cb1bdd4..ee95d3f969a 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmSmartCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmSmartCompletionTestGenerated.java @@ -1031,6 +1031,12 @@ public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/smart/functionLiterals"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); } + @TestMetadata("ExplicitParameterTypesRequired.kt") + public void testExplicitParameterTypesRequired() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/functionLiterals/ExplicitParameterTypesRequired.kt"); + doTest(fileName); + } + @TestMetadata("OutsideCallParenthesis1.kt") public void testOutsideCallParenthesis1() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/functionLiterals/OutsideCallParenthesis1.kt"); @@ -1452,6 +1458,45 @@ public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT } } + @TestMetadata("idea/idea-completion/testData/smart/lambdaSignature") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class LambdaSignature extends AbstractJvmSmartCompletionTest { + public void testAllFilesPresentInLambdaSignature() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/smart/lambdaSignature"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("ExplicitParameterTypesRequired.kt") + public void testExplicitParameterTypesRequired() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/lambdaSignature/ExplicitParameterTypesRequired.kt"); + doTest(fileName); + } + + @TestMetadata("MultipleParameters.kt") + public void testMultipleParameters() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/lambdaSignature/MultipleParameters.kt"); + doTest(fileName); + } + + @TestMetadata("NotAfterComma.kt") + public void testNotAfterComma() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/lambdaSignature/NotAfterComma.kt"); + doTest(fileName); + } + + @TestMetadata("NotInBody.kt") + public void testNotInBody() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/lambdaSignature/NotInBody.kt"); + doTest(fileName); + } + + @TestMetadata("SingleParameter.kt") + public void testSingleParameter() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/lambdaSignature/SingleParameter.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/idea-completion/testData/smart/multipleArgsItem") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/BasicCompletionHandlerTest.kt b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/BasicCompletionHandlerTest.kt index d7b1fb43fab..a0ae09afdec 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/BasicCompletionHandlerTest.kt +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/BasicCompletionHandlerTest.kt @@ -65,9 +65,9 @@ import java.io.File fun testNamedParametersCompletion() = doTest() - fun testNamedParametersCompletionOnEqual() = doTest(0, "paramTest", "paramTest =", null, '=') + fun testNamedParametersCompletionOnEqual() = doTest(0, "paramTest =", "paramTest =", null, '=') - fun testNamedParameterKeywordName() = doTest(1, "class", "class =", null, '\n') + fun testNamedParameterKeywordName() = doTest(1, "class =", "class =", null, '\n') fun testInsertJavaClassImport() = doTest() diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/weighers/BasicCompletionWeigherTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/weighers/BasicCompletionWeigherTestGenerated.java index c676243bd9b..3d07c4c7124 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/weighers/BasicCompletionWeigherTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/weighers/BasicCompletionWeigherTestGenerated.java @@ -102,6 +102,12 @@ public class BasicCompletionWeigherTestGenerated extends AbstractBasicCompletion doTest(fileName); } + @TestMetadata("LambdaSignature.kt") + public void testLambdaSignature() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/weighers/basic/LambdaSignature.kt"); + doTest(fileName); + } + @TestMetadata("LocalFileBeforeImported.kt") public void testLocalFileBeforeImported() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/weighers/basic/LocalFileBeforeImported.kt");