Completion of lambda parameters
Also changed policy for sorting of smart completion items in basic completion #KT-16800 Fixed #KT-12002 Fixed
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
-1
@@ -150,7 +150,6 @@ class BasicCompletionSession(
|
||||
val smartCompletionInBasicWeigher = SmartCompletionInBasicWeigher(smartCompletion, callTypeAndReceiver, resolutionFacade, bindingContext)
|
||||
sorter = sorter.weighBefore(KindWeigher.toString(),
|
||||
smartCompletionInBasicWeigher,
|
||||
SmartCompletionPriorityWeigher,
|
||||
CallableReferenceWeigher(callTypeAndReceiver.callType))
|
||||
}
|
||||
|
||||
|
||||
+197
@@ -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<KotlinType>, 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<LookupElement>()
|
||||
}
|
||||
}
|
||||
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<KotlinType> {
|
||||
return functionType.getValueParameterTypesFromFunctionType().map(TypeProjection::getType)
|
||||
}
|
||||
}
|
||||
+11
-4
@@ -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
|
||||
|
||||
+1
-2
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-150
@@ -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<LookupElement>()
|
||||
}
|
||||
}
|
||||
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<KotlinType> {
|
||||
return functionType.getValueParameterTypesFromFunctionType().map(TypeProjection::getType)
|
||||
}
|
||||
+5
-1
@@ -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
|
||||
}
|
||||
|
||||
|
||||
+50
-18
@@ -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<ExpectedInfo>,
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
+87
@@ -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<LookupElement>,
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -220,6 +220,8 @@ class SmartCompletion(
|
||||
|
||||
items.addNamedArgumentsWithLiteralValueItems(expectedInfos)
|
||||
|
||||
LambdaSignatureItems.addToCollection(items, expressionWithType, bindingContext, resolutionFacade)
|
||||
|
||||
if (!forBasicCompletion) {
|
||||
LambdaItems.addToCollection(items, expectedInfos)
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -3,4 +3,4 @@ fun small(param: Int) {
|
||||
|
||||
fun test() = small(<caret>)
|
||||
|
||||
// EXIST: {"lookupString":"param","tailText":" Int","itemText":"param ="}
|
||||
// EXIST: {"lookupString":"param =","tailText":" Int","itemText":"param ="}
|
||||
@@ -4,4 +4,4 @@ fun small(first: Int, second: Int) {
|
||||
fun test() = small(12, <caret>)
|
||||
|
||||
// ABSENT: first
|
||||
// EXIST: { lookupString:"second", itemText:"second =" }
|
||||
// EXIST: { lookupString:"second =", itemText:"second =" }
|
||||
|
||||
@@ -4,4 +4,4 @@ fun bar(s: String){
|
||||
foo("", "", <caret>)
|
||||
}
|
||||
|
||||
// EXIST: { lookupString:"option", itemText:"option =" }
|
||||
// EXIST: { lookupString:"option =", itemText:"option =" }
|
||||
|
||||
+2
-2
@@ -5,5 +5,5 @@ fun small(paramFirst: Sequence<String>, paramSecond: Comparable<kotlin.collectio
|
||||
|
||||
fun test() = small(<caret>)
|
||||
|
||||
// EXIST: {"lookupString":"paramSecond","tailText":" Comparable<List<Any>>","itemText":"paramSecond ="}
|
||||
// EXIST: {"lookupString":"paramFirst","tailText":" Sequence<String>","itemText":"paramFirst ="}
|
||||
// EXIST: {"lookupString":"paramSecond =","tailText":" Comparable<List<Any>>","itemText":"paramSecond ="}
|
||||
// EXIST: {"lookupString":"paramFirst =","tailText":" Sequence<String>","itemText":"paramFirst ="}
|
||||
|
||||
+2
-2
@@ -6,6 +6,6 @@ fun small(paramFirst: Int, paramSecond: Int) {
|
||||
fun test() = small(paramFirst = param<caret>)
|
||||
|
||||
// EXIST: paramTest
|
||||
// ABSENT: {"lookupString":"paramFirst","tailText":" Int","itemText":"paramFirst ="}
|
||||
// ABSENT: paramSecond
|
||||
// ABSENT: { itemText: "paramFirst =" }
|
||||
// ABSENT: { itemText: "paramSecond =" }
|
||||
// NOTHING_ELSE
|
||||
|
||||
+1
-1
@@ -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?" }
|
||||
|
||||
+4
-4
@@ -4,8 +4,8 @@ fun test() {
|
||||
foo("str", paramThird = "test", param<caret>)
|
||||
}
|
||||
|
||||
// ABSENT: paramFirst
|
||||
// EXIST: paramSecond
|
||||
// ABSENT: paramThird
|
||||
// EXIST: paramFourth
|
||||
// ABSENT: "paramFirst ="
|
||||
// EXIST: "paramSecond ="
|
||||
// ABSENT: "paramThird ="
|
||||
// EXIST: "paramFourth ="
|
||||
|
||||
|
||||
Vendored
+4
-4
@@ -5,7 +5,7 @@ fun test() {
|
||||
foo(12, param<caret>)
|
||||
}
|
||||
|
||||
// ABSENT: paramFirst
|
||||
// EXIST: {"lookupString":"paramSecond","tailText":" Int","itemText":"paramSecond ="}
|
||||
// ABSENT: paramThird
|
||||
// ABSENT: paramFourth
|
||||
// ABSENT: "paramFirst ="
|
||||
// EXIST: {"lookupString":"paramSecond =","tailText":" Int","itemText":"paramSecond ="}
|
||||
// ABSENT: "paramThird ="
|
||||
// ABSENT: "paramFourth ="
|
||||
+3
-3
@@ -4,6 +4,6 @@ fun foo(first: Int, second: Int, third: String) {
|
||||
fun test(p: Int) = foo(12, <caret>, third = "")
|
||||
|
||||
// EXIST: p
|
||||
// ABSENT: first
|
||||
// EXIST: third
|
||||
// EXIST: second
|
||||
// ABSENT: "first ="
|
||||
// EXIST: "third ="
|
||||
// EXIST: "second ="
|
||||
|
||||
+3
-3
@@ -4,6 +4,6 @@ fun foo(first: Int, second: Int, third: String) {
|
||||
fun test(p: Int) = foo(<caret>second = 3)
|
||||
|
||||
// EXIST: p
|
||||
// EXIST: first
|
||||
// EXIST: second
|
||||
// EXIST: third
|
||||
// EXIST: "first ="
|
||||
// EXIST: "second ="
|
||||
// EXIST: "third ="
|
||||
|
||||
@@ -6,5 +6,5 @@ fun other() {
|
||||
Foo(p<caret>)
|
||||
}
|
||||
|
||||
// EXIST: {"lookupString":"pFirst","tailText":" String?","itemText":"pFirst ="}
|
||||
// EXIST: {"lookupString":"pSecond","tailText":" Int","itemText":"pSecond ="}
|
||||
// EXIST: {"lookupString":"pFirst =","tailText":" String?","itemText":"pFirst ="}
|
||||
// EXIST: {"lookupString":"pSecond =","tailText":" Int","itemText":"pSecond ="}
|
||||
+3
-3
@@ -4,7 +4,7 @@ fun foo(first: Int, second: Int, third: String) {
|
||||
fun test(p: Int) = foo(12, third = "", <caret>)
|
||||
|
||||
// ABSENT: p
|
||||
// ABSENT: first
|
||||
// ABSENT: third
|
||||
// EXIST: second
|
||||
// ABSENT: "first ="
|
||||
// ABSENT: "third ="
|
||||
// EXIST: "second ="
|
||||
// NOTHING_ELSE
|
||||
|
||||
+2
-2
@@ -5,8 +5,8 @@ fun small(paramFirst: Int, paramSecond: Int) {
|
||||
|
||||
fun test() = small(param<caret>First = 12)
|
||||
|
||||
// EXIST: paramFirst
|
||||
// EXIST: paramSecond
|
||||
// EXIST: "paramFirst ="
|
||||
// EXIST: "paramSecond ="
|
||||
// EXIST: paramTest
|
||||
|
||||
// NOTHING_ELSE
|
||||
|
||||
@@ -3,4 +3,4 @@ import lib.KotlinClass
|
||||
fun test() = KotlinClass().foo(<caret>)
|
||||
|
||||
// ABSENT: p0
|
||||
// EXIST: { lookupString:"paramName", itemText:"paramName =" }
|
||||
// EXIST: { lookupString:"paramName =", itemText:"paramName =" }
|
||||
|
||||
+1
-1
@@ -4,5 +4,5 @@ fun paramFun() {}
|
||||
|
||||
fun test() {
|
||||
// Type '=', completion should be finishied
|
||||
foo(paramTest = <caret>)
|
||||
foo(paramTest =<caret>)
|
||||
}
|
||||
|
||||
@@ -4,5 +4,5 @@ fun test() {
|
||||
foo(xxx = 10, <caret>)
|
||||
}
|
||||
|
||||
// ELEMENT: yyy
|
||||
// ELEMENT: "yyy ="
|
||||
// CHAR: =
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
fun foo(xxx: Int, yyy: Int)
|
||||
|
||||
fun test() {
|
||||
foo(xxx = 10, yyy = <caret>)
|
||||
foo(xxx = 10, yyy =<caret>)
|
||||
}
|
||||
|
||||
// ELEMENT: yyy
|
||||
// ELEMENT: "yyy ="
|
||||
// CHAR: =
|
||||
|
||||
@@ -4,5 +4,5 @@ fun test() {
|
||||
foo(xxx = 10, <caret>)
|
||||
}
|
||||
|
||||
// ELEMENT: yyy
|
||||
// ELEMENT: "yyy ="
|
||||
// CHAR: ' '
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
fun foo(xxx: Int, yyy: Int)
|
||||
|
||||
fun test() {
|
||||
foo(xxx = 10, yyy = <caret>)
|
||||
foo(xxx = 10, yyy <caret>)
|
||||
}
|
||||
|
||||
// ELEMENT: yyy
|
||||
// ELEMENT: "yyy ="
|
||||
// CHAR: ' '
|
||||
|
||||
@@ -4,4 +4,4 @@ fun bar() {
|
||||
foo(<caret>)
|
||||
}
|
||||
|
||||
// ELEMENT: "{ Int -> ... }"
|
||||
// ELEMENT: "{ i -> ... }"
|
||||
|
||||
@@ -4,4 +4,4 @@ fun bar() {
|
||||
foo({ i -> <caret> })
|
||||
}
|
||||
|
||||
// ELEMENT: "{ Int -> ... }"
|
||||
// ELEMENT: "{ i -> ... }"
|
||||
|
||||
@@ -5,4 +5,4 @@ fun bar() {
|
||||
foo(<caret>)
|
||||
}
|
||||
|
||||
// ELEMENT: "{ String, StringBuilder -> ... }"
|
||||
// ELEMENT: "{ s, stringBuilder -> ... }"
|
||||
|
||||
@@ -5,4 +5,4 @@ fun bar() {
|
||||
foo({ s, stringBuilder -> <caret> })
|
||||
}
|
||||
|
||||
// ELEMENT: "{ String, StringBuilder -> ... }"
|
||||
// ELEMENT: "{ s, stringBuilder -> ... }"
|
||||
|
||||
@@ -4,7 +4,7 @@ fun bar(pInt: Int, pString: String) {
|
||||
foo(param2 = , <caret>)
|
||||
}
|
||||
|
||||
// EXIST: { lookupString: "param1", itemText: "param1 =" }
|
||||
// EXIST: { lookupString: "param3", itemText: "param3 =" }
|
||||
// EXIST: { lookupString: "param1 =", itemText: "param1 =" }
|
||||
// EXIST: { lookupString: "param3 =", itemText: "param3 =" }
|
||||
// ABSENT: param2
|
||||
// NOTHING_ELSE
|
||||
|
||||
@@ -4,7 +4,7 @@ fun bar(pInt: Int, pString: String) {
|
||||
foo(param2 = 1, <caret>)
|
||||
}
|
||||
|
||||
// EXIST: { lookupString: "param1", itemText: "param1 =" }
|
||||
// EXIST: { lookupString: "param3", itemText: "param3 =" }
|
||||
// EXIST: { lookupString: "param1 =", itemText: "param1 =" }
|
||||
// EXIST: { lookupString: "param3 =", itemText: "param3 =" }
|
||||
// ABSENT: param2
|
||||
// NOTHING_ELSE
|
||||
|
||||
@@ -4,5 +4,7 @@ fun bar() {
|
||||
foo(<caret>)
|
||||
}
|
||||
|
||||
// WITH_ORDER
|
||||
// EXIST: "{...}"
|
||||
// EXIST: "{ String -> ... }"
|
||||
// EXIST: "{ s -> ... }"
|
||||
// EXIST: "{ s: String -> ... }"
|
||||
|
||||
@@ -4,5 +4,7 @@ fun bar() {
|
||||
foo(<caret>)
|
||||
}
|
||||
|
||||
// WITH_ORDER
|
||||
// ABSENT: "{...}"
|
||||
// EXIST: "{ String, Int -> ... }"
|
||||
// EXIST: "{ s, i -> ... }"
|
||||
// EXIST: "{ s: String, i: Int -> ... }"
|
||||
|
||||
@@ -4,5 +4,7 @@ fun bar() {
|
||||
foo(<caret>)
|
||||
}
|
||||
|
||||
// WITH_ORDER
|
||||
// EXIST: "{...}"
|
||||
// EXIST: "{ Int -> ... }"
|
||||
// EXIST: "{ i -> ... }"
|
||||
// EXIST: "{ i: Int -> ... }"
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fun foo(p: (String, Int) -> Unit){}
|
||||
fun foo(p: (Char, xx: Any) -> Unit){}
|
||||
|
||||
fun bar() {
|
||||
foo(<caret>)
|
||||
}
|
||||
|
||||
// ABSENT: "{ s, i -> ... }"
|
||||
// ABSENT: "{ c, xx -> ... }"
|
||||
// EXIST: "{ String, Int -> ... }"
|
||||
// EXIST: "{ Char, xx -> ... }"
|
||||
+4
-2
@@ -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)<caret>
|
||||
}
|
||||
|
||||
// EXIST: "{ String, Char -> ... }"
|
||||
// WITH_ORDER
|
||||
// EXIST: "{ s, xx -> ... }"
|
||||
// EXIST: "{ s: String, xx: Char -> ... }"
|
||||
// ABSENT: handler
|
||||
+2
-1
@@ -5,5 +5,6 @@ fun bar(p: String.(Int) -> Unit) {
|
||||
}
|
||||
|
||||
// EXIST: "{...}"
|
||||
// EXIST: "{ Int -> ... }"
|
||||
// EXIST: "{ i -> ... }"
|
||||
// EXIST: "{ i: Int -> ... }"
|
||||
// ABSENT: p
|
||||
|
||||
+2
-1
@@ -4,5 +4,6 @@ fun bar(handler: (String, Char) -> Unit) {
|
||||
foo <caret>
|
||||
}
|
||||
|
||||
// EXIST: "{ String, Char -> ... }"
|
||||
// EXIST: "{ s, c -> ... }"
|
||||
// EXIST: "{ s: String, c: Char -> ... }"
|
||||
// ABSENT: handler
|
||||
+2
-1
@@ -4,5 +4,6 @@ fun bar(handler: (String, Char) -> Unit) {
|
||||
"".foo <caret>
|
||||
}
|
||||
|
||||
// EXIST: "{ String, Char -> ... }"
|
||||
// EXIST: "{ s, c -> ... }"
|
||||
// EXIST: "{ s: String, c: Char -> ... }"
|
||||
// ABSENT: handler
|
||||
+2
-1
@@ -4,5 +4,6 @@ fun bar(handler: (String, Char) -> Unit) {
|
||||
"" foo <caret>
|
||||
}
|
||||
|
||||
// EXIST: "{ String, Char -> ... }"
|
||||
// EXIST: "{ s, c -> ... }"
|
||||
// EXIST: "{ s: String, c: Char -> ... }"
|
||||
// EXIST: handler
|
||||
+2
-1
@@ -4,6 +4,7 @@ fun bar(handler: (String, Char) -> Unit) {
|
||||
foo(1)<caret>
|
||||
}
|
||||
|
||||
// EXIST: "{ String, Char -> ... }"
|
||||
// EXIST: "{ s, c -> ... }"
|
||||
// EXIST: "{ s: String, c: Char -> ... }"
|
||||
// ABSENT: null
|
||||
// ABSENT: handler
|
||||
+2
-1
@@ -4,5 +4,6 @@ fun bar(handler: (String, Char) -> Unit) {
|
||||
foo() <caret>
|
||||
}
|
||||
|
||||
// EXIST: "{ String, Char -> ... }"
|
||||
// EXIST: "{ s, c -> ... }"
|
||||
// EXIST: "{ s: String, c: Char -> ... }"
|
||||
// ABSENT: handler
|
||||
+2
-1
@@ -4,5 +4,6 @@ fun bar(handler: (String, Char) -> Unit) {
|
||||
foo <caret>
|
||||
}
|
||||
|
||||
// EXIST: "{ String, Char -> ... }"
|
||||
// EXIST: "{ s, c -> ... }"
|
||||
// EXIST: "{ s: String, c: Char -> ... }"
|
||||
// ABSENT: handler
|
||||
+2
-1
@@ -4,5 +4,6 @@ fun bar(handler: (String, Char) -> Unit) {
|
||||
foo() <caret>
|
||||
}
|
||||
|
||||
// EXIST: "{ String, Char -> ... }"
|
||||
// EXIST: "{ s, c -> ... }"
|
||||
// EXIST: "{ s: String, c: Char -> ... }"
|
||||
// ABSENT: handler
|
||||
+2
-1
@@ -4,5 +4,6 @@ fun bar(handler: (String, Char) -> Unit) {
|
||||
foo(1, 2) <caret>
|
||||
}
|
||||
|
||||
// EXIST: "{ String, Char -> ... }"
|
||||
// EXIST: "{ s, c -> ... }"
|
||||
// EXIST: "{ s: String, c: Char -> ... }"
|
||||
// ABSENT: handler
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fun foo(p: (String, Int) -> Unit){}
|
||||
fun foo(p: (Char, xx: Any) -> Unit){}
|
||||
|
||||
fun bar() {
|
||||
foo { <caret> }
|
||||
}
|
||||
|
||||
// EXIST: "String, Int ->"
|
||||
// EXIST: "Char, xx ->"
|
||||
// ABSENT: "s, i ->"
|
||||
// ABSENT: "c, xx ->"
|
||||
@@ -0,0 +1,7 @@
|
||||
fun foo(p: Int) {
|
||||
"abc".fold(1) { <caret> }
|
||||
}
|
||||
|
||||
// EXIST: p
|
||||
// EXIST: "acc: Int, c: Char ->"
|
||||
// EXIST: "acc, c ->"
|
||||
@@ -0,0 +1,5 @@
|
||||
fun foo(p: Int) {
|
||||
"abc".fold(1) { acc, <caret> }
|
||||
}
|
||||
|
||||
// NOTHING_ELSE
|
||||
@@ -0,0 +1,7 @@
|
||||
fun foo(p: Int) {
|
||||
"abc".fold(1) { acc, c -> <caret> }
|
||||
}
|
||||
|
||||
// EXIST: p
|
||||
// ABSENT: "acc: Int, c: Char ->"
|
||||
// ABSENT: "acc, c ->"
|
||||
@@ -0,0 +1,7 @@
|
||||
fun foo(p: Boolean) {
|
||||
"abc".filter { <caret> }
|
||||
}
|
||||
|
||||
// EXIST: p
|
||||
// EXIST: "c ->"
|
||||
// EXIST: "c: Char ->"
|
||||
@@ -0,0 +1,8 @@
|
||||
fun <R> String.fold(initial: R, operation: (acc: R, Char) -> R): R = TODO()
|
||||
|
||||
fun foo(p: Int) {
|
||||
"abc".fold(1) { <caret> }
|
||||
}
|
||||
|
||||
// ORDER: "acc, c ->"
|
||||
// ORDER: "acc: Int, c: Char ->"
|
||||
@@ -20,6 +20,6 @@ fun test(listParam: Int) {
|
||||
// ORDER: listImportedVal
|
||||
// ORDER: listThisFileFun
|
||||
// ORDER: listImportedFun
|
||||
// ORDER: listMatch
|
||||
// ORDER: listNew
|
||||
// ORDER: "listMatch ="
|
||||
// ORDER: "listNew ="
|
||||
// ORDER: listFunNotMatchingType
|
||||
|
||||
@@ -6,6 +6,6 @@ fun test(tri: Boolean, trb: Int) {
|
||||
|
||||
// ORDER: true
|
||||
// ORDER: tri
|
||||
// ORDER: tra
|
||||
// ORDER: "tra ="
|
||||
// ORDER: trb
|
||||
// ORDER: try
|
||||
|
||||
@@ -11,5 +11,5 @@ fun test(insa: Any) {
|
||||
}
|
||||
|
||||
// ORDER: instance
|
||||
// ORDER: insp
|
||||
// ORDER: "insp ="
|
||||
// ORDER: insa
|
||||
|
||||
@@ -8,5 +8,5 @@ fun bar(b: I2, a: I1, c: I1) {
|
||||
}
|
||||
|
||||
// ORDER: a
|
||||
// ORDER: c
|
||||
// ORDER: "a, b, c"
|
||||
// ORDER: c
|
||||
|
||||
+2
-1
@@ -8,5 +8,6 @@ fun f() {
|
||||
}
|
||||
|
||||
// ORDER: {...}
|
||||
// ORDER: { Int -> ... }
|
||||
// ORDER: { i -> ... }
|
||||
// ORDER: { i: Int -> ... }
|
||||
// ORDER: ::fff2
|
||||
|
||||
@@ -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
|
||||
|
||||
+45
@@ -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)
|
||||
|
||||
+2
-2
@@ -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()
|
||||
|
||||
|
||||
+6
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user