From 5fc6525db6367dbcc23e092696e891a07105aa81 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Wed, 19 Aug 2015 20:12:48 +0300 Subject: [PATCH] Completion to insert type arguments for a call when they are likely required --- .../idea/completion/BasicCompletionSession.kt | 3 + .../idea/completion/CompletionSession.kt | 13 +-- .../completion/KDocCompletionContributor.kt | 1 + .../idea/completion/KeywordCompletion.kt | 2 +- .../idea/completion/LookupElementFactory.kt | 94 ++++++++++++++----- .../completion/LookupElementsCollector.kt | 4 +- .../completion/PackageDirectiveCompletion.kt | 2 +- .../handlers/KotlinFunctionInsertHandler.kt | 73 +++++++------- .../smart/SmartCompletionSession.kt | 20 ++-- .../smart/TypeInstantiationItems.kt | 9 +- .../ExpectedTypeDoesNotHelp.kt | 7 ++ .../ExpectedTypeDoesNotHelp.kt.after | 7 ++ .../ExpectedTypeDoesNotHelp2.kt | 7 ++ .../ExpectedTypeDoesNotHelp2.kt.after | 7 ++ .../ExplicitLambdaSignature.kt | 8 ++ .../ExplicitLambdaSignature.kt.after | 8 ++ .../typeArgsForCall/FunctionTypeParameter1.kt | 7 ++ .../FunctionTypeParameter1.kt.after | 7 ++ .../typeArgsForCall/FunctionTypeParameter2.kt | 5 + .../FunctionTypeParameter2.kt.after | 5 + .../basic/typeArgsForCall/HasExpectedType.kt | 7 ++ .../typeArgsForCall/HasExpectedType.kt.after | 7 ++ .../NotAllTypeArgumentsFromParameters.kt | 7 ++ ...NotAllTypeArgumentsFromParameters.kt.after | 7 ++ .../handlers/basic/typeArgsForCall/Simple.kt | 9 ++ .../basic/typeArgsForCall/Simple.kt.after | 9 ++ .../TypeArgumentsFromParameters.kt | 7 ++ .../TypeArgumentsFromParameters.kt.after | 7 ++ .../smart/DoNotInsertTypeArguments.kt | 7 ++ .../smart/DoNotInsertTypeArguments.kt.after | 7 ++ .../handlers/smart/InsertTypeArguments.kt | 7 ++ .../smart/InsertTypeArguments.kt.after | 7 ++ .../BasicCompletionHandlerTestGenerated.java | 63 +++++++++++++ .../SmartCompletionHandlerTestGenerated.java | 12 +++ 34 files changed, 372 insertions(+), 80 deletions(-) create mode 100644 idea/idea-completion/testData/handlers/basic/typeArgsForCall/ExpectedTypeDoesNotHelp.kt create mode 100644 idea/idea-completion/testData/handlers/basic/typeArgsForCall/ExpectedTypeDoesNotHelp.kt.after create mode 100644 idea/idea-completion/testData/handlers/basic/typeArgsForCall/ExpectedTypeDoesNotHelp2.kt create mode 100644 idea/idea-completion/testData/handlers/basic/typeArgsForCall/ExpectedTypeDoesNotHelp2.kt.after create mode 100644 idea/idea-completion/testData/handlers/basic/typeArgsForCall/ExplicitLambdaSignature.kt create mode 100644 idea/idea-completion/testData/handlers/basic/typeArgsForCall/ExplicitLambdaSignature.kt.after create mode 100644 idea/idea-completion/testData/handlers/basic/typeArgsForCall/FunctionTypeParameter1.kt create mode 100644 idea/idea-completion/testData/handlers/basic/typeArgsForCall/FunctionTypeParameter1.kt.after create mode 100644 idea/idea-completion/testData/handlers/basic/typeArgsForCall/FunctionTypeParameter2.kt create mode 100644 idea/idea-completion/testData/handlers/basic/typeArgsForCall/FunctionTypeParameter2.kt.after create mode 100644 idea/idea-completion/testData/handlers/basic/typeArgsForCall/HasExpectedType.kt create mode 100644 idea/idea-completion/testData/handlers/basic/typeArgsForCall/HasExpectedType.kt.after create mode 100644 idea/idea-completion/testData/handlers/basic/typeArgsForCall/NotAllTypeArgumentsFromParameters.kt create mode 100644 idea/idea-completion/testData/handlers/basic/typeArgsForCall/NotAllTypeArgumentsFromParameters.kt.after create mode 100644 idea/idea-completion/testData/handlers/basic/typeArgsForCall/Simple.kt create mode 100644 idea/idea-completion/testData/handlers/basic/typeArgsForCall/Simple.kt.after create mode 100644 idea/idea-completion/testData/handlers/basic/typeArgsForCall/TypeArgumentsFromParameters.kt create mode 100644 idea/idea-completion/testData/handlers/basic/typeArgsForCall/TypeArgumentsFromParameters.kt.after create mode 100644 idea/idea-completion/testData/handlers/smart/DoNotInsertTypeArguments.kt create mode 100644 idea/idea-completion/testData/handlers/smart/DoNotInsertTypeArguments.kt.after create mode 100644 idea/idea-completion/testData/handlers/smart/InsertTypeArguments.kt create mode 100644 idea/idea-completion/testData/handlers/smart/InsertTypeArguments.kt.after 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 f50bcad4680..0208e6065cd 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 @@ -103,6 +103,9 @@ class BasicCompletionSession(configuration: CompletionSessionConfiguration, ) } + override val expectedInfos: Collection + get() = smartCompletion?.expectedInfos ?: emptyList() + private fun calcCompletionKind(): CompletionKind { if (NamedArgumentCompletion.isOnlyNamedArgumentExpected(position)) { return CompletionKind.NAMED_ARGUMENTS_ONLY diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt index 7cd56730488..01a52fe198e 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt @@ -51,6 +51,7 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastManager import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter +import org.jetbrains.kotlin.types.JetType import org.jetbrains.kotlin.types.typeUtil.makeNotNullable import org.jetbrains.kotlin.util.capitalizeDecapitalize.decapitalizeSmart import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance @@ -142,10 +143,11 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC protected val receiversData: ReferenceVariantsHelper.ReceiversData? = nameExpression?.let { referenceVariantsHelper.getReferenceVariantsReceivers(it) } protected val lookupElementFactory: LookupElementFactory = run { + var receiverTypes = emptyList() if (receiversData != null) { val dataFlowInfo = bindingContext.getDataFlowInfo(expression) - var receiverTypes = receiversData.receivers.flatMap { receiverValue -> + receiverTypes = receiversData.receivers.flatMap { receiverValue -> val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiverValue, bindingContext, moduleDescriptor) if (dataFlowValue.isPredictable) { // we don't include smart cast receiver types for "unpredictable" receiver value to mark members grayed resolutionFacade.frontendService() @@ -159,12 +161,9 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC if (receiversData.callType == CallType.SAFE) { receiverTypes = receiverTypes.map { it.makeNotNullable() } } + } - LookupElementFactory(resolutionFacade, receiverTypes) - } - else { - LookupElementFactory(resolutionFacade, emptyList()) - } + LookupElementFactory(resolutionFacade, receiverTypes, { expectedInfos }) } private val collectorContext = if (expression?.getParent() is JetSimpleNameStringTemplateEntry) @@ -230,6 +229,8 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC protected abstract val descriptorKindFilter: DescriptorKindFilter? + protected abstract val expectedInfos: Collection + protected open fun createSorter(): CompletionSorter { var sorter = CompletionSorter.defaultSorter(parameters, prefixMatcher)!! diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KDocCompletionContributor.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KDocCompletionContributor.kt index ea3039e1684..b59de0f9632 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KDocCompletionContributor.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KDocCompletionContributor.kt @@ -65,6 +65,7 @@ object KDocNameCompletionProvider: CompletionProvider() { class KDocNameCompletionSession(parameters: CompletionParameters, resultSet: CompletionResultSet): CompletionSession(CompletionSessionConfiguration(parameters), parameters, resultSet) { override val descriptorKindFilter: DescriptorKindFilter? get() = null + override val expectedInfos: Collection get() = emptyList() override fun doComplete() { val position = parameters.getPosition().getParentOfType(false) ?: return diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KeywordCompletion.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KeywordCompletion.kt index 7035f3d15d2..d52db0feea1 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KeywordCompletion.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/KeywordCompletion.kt @@ -77,7 +77,7 @@ object KeywordCompletion { .withInsertHandler(if (keywordToken !in FUNCTION_KEYWORDS) KotlinKeywordInsertHandler else - KotlinFunctionInsertHandler.NO_PARAMETERS_HANDLER) + KotlinFunctionInsertHandler(needTypeArguments = false, needValueArguments = false)) consumer(element) } } 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 3116ef2d743..3145489310e 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 @@ -29,6 +29,7 @@ import org.jetbrains.kotlin.idea.JetDescriptorIconProvider import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.completion.handlers.* import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject +import org.jetbrains.kotlin.idea.util.fuzzyReturnType import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name @@ -42,6 +43,8 @@ import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor import org.jetbrains.kotlin.types.JetType import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf +import org.jetbrains.kotlin.utils.addIfNotNull +import java.util.* public data class PackageLookupObject(val fqName: FqName) : DeclarationLookupObject { override val psiElement: PsiElement? get() = null @@ -59,8 +62,11 @@ public data class PackageLookupObject(val fqName: FqName) : DeclarationLookupObj public class LookupElementFactory( private val resolutionFacade: ResolutionFacade, - private val receiverTypes: Collection + private val receiverTypes: Collection, + expectedInfosCalculator: () -> Collection ) { + private val expectedInfos by lazy { expectedInfosCalculator() } + public fun createLookupElement( descriptor: DeclarationDescriptor, boldImmediateMembers: Boolean, @@ -368,36 +374,74 @@ public class LookupElementFactory( return typeParameter.containingDeclaration == original } - companion object { - public fun getDefaultInsertHandler(descriptor: DeclarationDescriptor): InsertHandler { - return when (descriptor) { - is FunctionDescriptor -> { - val parameters = descriptor.getValueParameters() - when (parameters.size()) { - 0 -> KotlinFunctionInsertHandler.NO_PARAMETERS_HANDLER + public fun getDefaultInsertHandler(descriptor: DeclarationDescriptor): InsertHandler { + return when (descriptor) { + is FunctionDescriptor -> { + val needTypeArguments = needTypeArguments(descriptor) + val parameters = descriptor.valueParameters + when (parameters.size()) { + 0 -> KotlinFunctionInsertHandler(needTypeArguments, needValueArguments = false) - 1 -> { - val parameterType = parameters.single().getType() - if (KotlinBuiltIns.isExactFunctionOrExtensionFunctionType(parameterType)) { - val parameterCount = KotlinBuiltIns.getParameterTypeProjectionsFromFunctionType(parameterType).size() - if (parameterCount <= 1) { - // otherwise additional item with lambda template is to be added - return KotlinFunctionInsertHandler(CaretPosition.IN_BRACKETS, GenerateLambdaInfo(parameterType, false)) - } + 1 -> { + val parameterType = parameters.single().getType() + if (KotlinBuiltIns.isExactFunctionOrExtensionFunctionType(parameterType)) { + val parameterCount = KotlinBuiltIns.getParameterTypeProjectionsFromFunctionType(parameterType).size() + if (parameterCount <= 1) { + // otherwise additional item with lambda template is to be added + return KotlinFunctionInsertHandler(needTypeArguments, needValueArguments = true, lambdaInfo = GenerateLambdaInfo(parameterType, false)) } - KotlinFunctionInsertHandler.WITH_PARAMETERS_HANDLER } - - else -> KotlinFunctionInsertHandler.WITH_PARAMETERS_HANDLER + KotlinFunctionInsertHandler(needTypeArguments, needValueArguments = true) } + + else -> KotlinFunctionInsertHandler(needTypeArguments, needValueArguments = true) } - - is PropertyDescriptor -> KotlinPropertyInsertHandler - - is ClassifierDescriptor -> KotlinClassifierInsertHandler - - else -> BaseDeclarationInsertHandler() } + + is PropertyDescriptor -> KotlinPropertyInsertHandler + + is ClassifierDescriptor -> KotlinClassifierInsertHandler + + else -> BaseDeclarationInsertHandler() } } + + private fun needTypeArguments(function: FunctionDescriptor): Boolean { + if (function.typeParameters.isEmpty()) return false + + val originalFunction = function.original + val typeParameters = originalFunction.typeParameters + + val potentiallyInferred = HashSet() + + fun addPotentiallyInferred(type: JetType) { + val descriptor = type.constructor.declarationDescriptor as? TypeParameterDescriptor + if (descriptor != null && descriptor in typeParameters) { + potentiallyInferred.add(descriptor) + } + + if (KotlinBuiltIns.isExactFunctionOrExtensionFunctionType(type) && KotlinBuiltIns.getParameterTypeProjectionsFromFunctionType(type).size() <= 1) { + // do not rely on inference from input of function type with one or no arguments - use only return type of functional type + addPotentiallyInferred(KotlinBuiltIns.getReturnTypeFromFunctionType(type)) + return + } + + for (argument in type.arguments) { + if (!argument.isStarProjection) { // otherwise we can fall into infinite recursion + addPotentiallyInferred(argument.type) + } + } + } + + originalFunction.extensionReceiverParameter?.type?.let { addPotentiallyInferred(it) } + originalFunction.valueParameters.forEach { addPotentiallyInferred(it.type) } + + val returnType = originalFunction.returnType + // check that there is an expected type and return value from the function can potentially match it + if (returnType != null && expectedInfos.any { it.fuzzyType?.checkIsSuperTypeOf(originalFunction.fuzzyReturnType()!!) != null }) { + addPotentiallyInferred(returnType) + } + + return originalFunction.typeParameters.any { it !in potentiallyInferred } + } } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementsCollector.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementsCollector.kt index 83a36ad666f..788672b6ee5 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementsCollector.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/LookupElementsCollector.kt @@ -138,6 +138,8 @@ class LookupElementsCollector( private fun addSpecialFunctionDescriptorElement(descriptor: FunctionDescriptor, parameterType: JetType) { var lookupElement = lookupElementFactory.createLookupElement(descriptor, true) + val needTypeArguments = (lookupElementFactory.getDefaultInsertHandler(descriptor) as KotlinFunctionInsertHandler).needTypeArguments + val lambdaInfo = GenerateLambdaInfo(parameterType, true) lookupElement = object : LookupElementDecorator(lookupElement) { override fun renderElement(presentation: LookupElementPresentation) { @@ -150,7 +152,7 @@ class LookupElementsCollector( } override fun handleInsert(context: InsertionContext) { - KotlinFunctionInsertHandler(CaretPosition.IN_BRACKETS, GenerateLambdaInfo(parameterType, true)).handleInsert(context, this) + KotlinFunctionInsertHandler(needTypeArguments, needValueArguments = true, lambdaInfo = lambdaInfo).handleInsert(context, this) } } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/PackageDirectiveCompletion.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/PackageDirectiveCompletion.kt index abd4e953c9b..e7ca51a7cc5 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/PackageDirectiveCompletion.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/PackageDirectiveCompletion.kt @@ -54,7 +54,7 @@ object PackageDirectiveCompletion { val variants = ReferenceVariantsHelper(bindingContext, resolutionFacade, { true }).getPackageReferenceVariants(expression, prefixMatcher.asNameFilter()) for (variant in variants) { - val lookupElement = LookupElementFactory(resolutionFacade, listOf()).createLookupElement(variant, false) + val lookupElement = LookupElementFactory(resolutionFacade, emptyList(), { emptyList() }).createLookupElement(variant, false) if (!lookupElement.getLookupString().contains(DUMMY_IDENTIFIER)) { result.addElement(lookupElement) } 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 abd5ce245e5..880e884d875 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 @@ -35,24 +35,18 @@ import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.types.JetType -enum class CaretPosition { - IN_BRACKETS, - AFTER_BRACKETS -} - data class GenerateLambdaInfo(val lambdaType: JetType, val explicitParameters: Boolean) -class KotlinFunctionInsertHandler(val caretPosition: CaretPosition, val lambdaInfo: GenerateLambdaInfo?) : KotlinCallableInsertHandler() { - init { - if (caretPosition == CaretPosition.AFTER_BRACKETS && lambdaInfo != null) { - throw IllegalArgumentException("CaretPosition.AFTER_BRACKETS with lambdaInfo != null combination is not supported") - } - } +class KotlinFunctionInsertHandler( + val needTypeArguments: Boolean, + val needValueArguments: Boolean, + val lambdaInfo: GenerateLambdaInfo? = null +) : KotlinCallableInsertHandler() { public override fun handleInsert(context: InsertionContext, item: LookupElement) { super.handleInsert(context, item) - val psiDocumentManager = PsiDocumentManager.getInstance(context.getProject()) + val psiDocumentManager = PsiDocumentManager.getInstance(context.project) psiDocumentManager.commitAllDocuments() psiDocumentManager.doPostponedOperationsAndUnblockDocument(context.getDocument()) @@ -88,31 +82,46 @@ class KotlinFunctionInsertHandler(val caretPosition: CaretPosition, val lambdaIn context.setAddCompletionChar(false) } - var offset = context.getTailOffset() - val document = context.getDocument() - val chars = document.getCharsSequence() + var offset = context.tailOffset + val document = context.document + val editor = context.editor + val project = context.project + val chars = document.charsSequence val insertLambda = lambdaInfo != null && completionChar != '(' && !(completionChar == '\t' && chars.isCharAt(offset, '(')) val openingBracket = if (insertLambda) '{' else '(' val closingBracket = if (insertLambda) '}' else ')' + var insertTypeArguments = needTypeArguments && (completionChar == '\n' || completionChar == '\r') + if (completionChar == Lookup.REPLACE_SELECT_CHAR) { val offset1 = chars.skipSpaces(offset) if (offset1 < chars.length()) { if (chars[offset1] == '<') { - PsiDocumentManager.getInstance(context.getProject()).commitDocument(document) + PsiDocumentManager.getInstance(project).commitDocument(document) val token = context.getFile().findElementAt(offset1)!! if (token.getNode().getElementType() == JetTokens.LT) { val parent = token.getParent() if (parent is JetTypeArgumentList && parent.getText().indexOf('\n') < 0/* if type argument list is on multiple lines this is more likely wrong parsing*/) { offset = parent.endOffset + insertTypeArguments = false } } } } } + if (insertLambda && lambdaInfo!!.explicitParameters) { + insertTypeArguments = false + } + + if (insertTypeArguments) { + document.insertString(offset, "<>") + editor.caretModel.moveToOffset(offset + 1) + offset += 2 + } + var openingBracketOffset = chars.indexOfSkippingSpace(openingBracket, offset) var closeBracketOffset = openingBracketOffset?.let { chars.indexOfSkippingSpace(closingBracket, it + 1) } var inBracketsShift = 0 @@ -127,7 +136,7 @@ class KotlinFunctionInsertHandler(val caretPosition: CaretPosition, val lambdaIn context.setAddCompletionChar(false) } - if (isInsertSpacesInOneLineFunctionEnabled(context.getProject())) { + if (isInsertSpacesInOneLineFunctionEnabled(project)) { document.insertString(offset, " { }") inBracketsShift = 1 } @@ -138,22 +147,23 @@ class KotlinFunctionInsertHandler(val caretPosition: CaretPosition, val lambdaIn else { document.insertString(offset, "()") } - PsiDocumentManager.getInstance(context.getProject()).commitDocument(document) + PsiDocumentManager.getInstance(project).commitDocument(document) openingBracketOffset = chars.indexOfSkippingSpace(openingBracket, offset)!! closeBracketOffset = chars.indexOfSkippingSpace(closingBracket, openingBracketOffset + 1)!! } - val editor = context.getEditor() - if (shouldPlaceCaretInBrackets(completionChar) || closeBracketOffset == null) { - editor.getCaretModel().moveToOffset(openingBracketOffset + 1 + inBracketsShift) - AutoPopupController.getInstance(context.getProject())?.autoPopupParameterInfo(editor, offsetElement) - } - else { - editor.getCaretModel().moveToOffset(closeBracketOffset + 1) + if (!insertTypeArguments) { + if (shouldPlaceCaretInBrackets(completionChar) || closeBracketOffset == null) { + editor.caretModel.moveToOffset(openingBracketOffset + 1 + inBracketsShift) + AutoPopupController.getInstance(project)?.autoPopupParameterInfo(editor, offsetElement) + } + else { + editor.caretModel.moveToOffset(closeBracketOffset + 1) + } } - PsiDocumentManager.getInstance(context.getProject()).commitDocument(document) + PsiDocumentManager.getInstance(project).commitDocument(document) if (insertLambda && lambdaInfo!!.explicitParameters) { insertLambdaTemplate(context, TextRange(openingBracketOffset, closeBracketOffset!! + 1), lambdaInfo!!.lambdaType) @@ -163,14 +173,9 @@ class KotlinFunctionInsertHandler(val caretPosition: CaretPosition, val lambdaIn private fun shouldPlaceCaretInBrackets(completionChar: Char): Boolean { if (completionChar == ',' || completionChar == '.' || completionChar == '=') return false if (completionChar == '(') return true - return caretPosition == CaretPosition.IN_BRACKETS + return needValueArguments } - companion object { - public val NO_PARAMETERS_HANDLER: KotlinFunctionInsertHandler = KotlinFunctionInsertHandler(CaretPosition.AFTER_BRACKETS, null) - public val WITH_PARAMETERS_HANDLER: KotlinFunctionInsertHandler = KotlinFunctionInsertHandler(CaretPosition.IN_BRACKETS, null) - - private fun isInsertSpacesInOneLineFunctionEnabled(project: Project) - = CodeStyleSettingsManager.getSettings(project).getCustomSettings(javaClass())!!.INSERT_WHITESPACES_IN_SIMPLE_ONE_LINE_METHOD - } + private fun isInsertSpacesInOneLineFunctionEnabled(project: Project) + = CodeStyleSettingsManager.getSettings(project).getCustomSettings(javaClass())!!.INSERT_WHITESPACES_IN_SIMPLE_ONE_LINE_METHOD } \ No newline at end of file diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletionSession.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletionSession.kt index 794d350d413..83078ba356c 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletionSession.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/SmartCompletionSession.kt @@ -38,6 +38,17 @@ class SmartCompletionSession(configuration: CompletionSessionConfiguration, para // we do not include SAM-constructors because they are handled separately and adding them requires iterating of java classes override val descriptorKindFilter = DescriptorKindFilter.VALUES exclude SamConstructorDescriptorKindExclude + private val smartCompletion by lazy { + expression?.let { + SmartCompletion(it, resolutionFacade, + bindingContext, isVisibleFilter, inDescriptor, prefixMatcher, originalSearchScope, + toFromOriginalFileMapper, lookupElementFactory) + } + } + + override val expectedInfos: Collection + get() = smartCompletion?.expectedInfos ?: emptyList() + override fun doComplete() { if (NamedArgumentCompletion.isOnlyNamedArgumentExpected(position)) { NamedArgumentCompletion.complete(position, collector, bindingContext) @@ -47,16 +58,11 @@ class SmartCompletionSession(configuration: CompletionSessionConfiguration, para if (expression != null) { addFunctionLiteralArgumentCompletions() - val completion = SmartCompletion( - expression, resolutionFacade, bindingContext, isVisibleFilter, inDescriptor, - prefixMatcher, originalSearchScope, toFromOriginalFileMapper, lookupElementFactory - ) - - val (additionalItems, inheritanceSearcher) = completion.additionalItems() + val (additionalItems, inheritanceSearcher) = smartCompletion!!.additionalItems() collector.addElements(additionalItems) if (nameExpression != null) { - val filter = completion.descriptorFilter + val filter = smartCompletion!!.descriptorFilter if (filter != null) { referenceVariants.forEach { collector.addElements(filter(it)) } flushToResultSet() diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/TypeInstantiationItems.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/TypeInstantiationItems.kt index beba4cc3fe2..8455dad9c34 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/TypeInstantiationItems.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/TypeInstantiationItems.kt @@ -29,7 +29,6 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.idea.completion.* -import org.jetbrains.kotlin.idea.completion.handlers.CaretPosition import org.jetbrains.kotlin.idea.completion.handlers.KotlinFunctionInsertHandler import org.jetbrains.kotlin.idea.core.overrideImplement.ImplementMethodsHandler import org.jetbrains.kotlin.idea.core.psiClassToDescriptor @@ -185,9 +184,9 @@ class TypeInstantiationItems( } val baseInsertHandler = when (visibleConstructors.size()) { - 0 -> KotlinFunctionInsertHandler.NO_PARAMETERS_HANDLER - 1 -> LookupElementFactory.getDefaultInsertHandler(visibleConstructors.single()) as KotlinFunctionInsertHandler - else -> KotlinFunctionInsertHandler.WITH_PARAMETERS_HANDLER + 0 -> KotlinFunctionInsertHandler(needTypeArguments = false, needValueArguments = false) + 1 -> lookupElementFactory.getDefaultInsertHandler(visibleConstructors.single()) as KotlinFunctionInsertHandler + else -> KotlinFunctionInsertHandler(needTypeArguments = false, needValueArguments = true) } insertHandler = object : InsertHandler { @@ -200,7 +199,7 @@ class TypeInstantiationItems( shortenReferences(context, context.getStartOffset(), context.getTailOffset()) } } - if (baseInsertHandler.caretPosition == CaretPosition.IN_BRACKETS) { + if (baseInsertHandler.needValueArguments) { lookupElement = lookupElement.keepOldArgumentListOnTab() } if (baseInsertHandler.lambdaInfo != null) { diff --git a/idea/idea-completion/testData/handlers/basic/typeArgsForCall/ExpectedTypeDoesNotHelp.kt b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/ExpectedTypeDoesNotHelp.kt new file mode 100644 index 00000000000..23214acfb2c --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/ExpectedTypeDoesNotHelp.kt @@ -0,0 +1,7 @@ +public inline fun Iterable<*>.foo(): String { } + +fun f(list: List): String { + return list. +} + +// ELEMENT: foo diff --git a/idea/idea-completion/testData/handlers/basic/typeArgsForCall/ExpectedTypeDoesNotHelp.kt.after b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/ExpectedTypeDoesNotHelp.kt.after new file mode 100644 index 00000000000..baadd0a9722 --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/ExpectedTypeDoesNotHelp.kt.after @@ -0,0 +1,7 @@ +public inline fun Iterable<*>.foo(): String { } + +fun f(list: List): String { + return list.foo<>() +} + +// ELEMENT: foo diff --git a/idea/idea-completion/testData/handlers/basic/typeArgsForCall/ExpectedTypeDoesNotHelp2.kt b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/ExpectedTypeDoesNotHelp2.kt new file mode 100644 index 00000000000..309b2ea505b --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/ExpectedTypeDoesNotHelp2.kt @@ -0,0 +1,7 @@ +public inline fun Iterable<*>.myFilterIsInstance(): Collection { } + +fun foo(list: List): String { + return list. +} + +// ELEMENT: myFilterIsInstance diff --git a/idea/idea-completion/testData/handlers/basic/typeArgsForCall/ExpectedTypeDoesNotHelp2.kt.after b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/ExpectedTypeDoesNotHelp2.kt.after new file mode 100644 index 00000000000..8214d46bf9d --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/ExpectedTypeDoesNotHelp2.kt.after @@ -0,0 +1,7 @@ +public inline fun Iterable<*>.myFilterIsInstance(): Collection { } + +fun foo(list: List): String { + return list.myFilterIsInstance<>() +} + +// ELEMENT: myFilterIsInstance diff --git a/idea/idea-completion/testData/handlers/basic/typeArgsForCall/ExplicitLambdaSignature.kt b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/ExplicitLambdaSignature.kt new file mode 100644 index 00000000000..71b1bfb542b --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/ExplicitLambdaSignature.kt @@ -0,0 +1,8 @@ +fun foo(p : (T, Int) -> Boolean){} + +fun main(args: Array) { + fo +} + +// ELEMENT: foo +// TAIL_TEXT: " { T, Int -> ... } (p: (T, Int) -> Boolean) ()" diff --git a/idea/idea-completion/testData/handlers/basic/typeArgsForCall/ExplicitLambdaSignature.kt.after b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/ExplicitLambdaSignature.kt.after new file mode 100644 index 00000000000..1812e333026 --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/ExplicitLambdaSignature.kt.after @@ -0,0 +1,8 @@ +fun foo(p : (T, Int) -> Boolean){} + +fun main(args: Array) { + foo { t, i -> } +} + +// ELEMENT: foo +// TAIL_TEXT: " { T, Int -> ... } (p: (T, Int) -> Boolean) ()" diff --git a/idea/idea-completion/testData/handlers/basic/typeArgsForCall/FunctionTypeParameter1.kt b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/FunctionTypeParameter1.kt new file mode 100644 index 00000000000..bb938ac8c28 --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/FunctionTypeParameter1.kt @@ -0,0 +1,7 @@ +fun T1.foo(handler: (T2) -> Boolean) {} + +fun f() { + "". +} + +// ELEMENT: foo diff --git a/idea/idea-completion/testData/handlers/basic/typeArgsForCall/FunctionTypeParameter1.kt.after b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/FunctionTypeParameter1.kt.after new file mode 100644 index 00000000000..5c13e2858f2 --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/FunctionTypeParameter1.kt.after @@ -0,0 +1,7 @@ +fun T1.foo(handler: (T2) -> Boolean) {} + +fun f() { + "".foo<> { } +} + +// ELEMENT: foo diff --git a/idea/idea-completion/testData/handlers/basic/typeArgsForCall/FunctionTypeParameter2.kt b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/FunctionTypeParameter2.kt new file mode 100644 index 00000000000..ee18858ffe3 --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/FunctionTypeParameter2.kt @@ -0,0 +1,5 @@ +fun f(list: List) { + list. +} + +// ELEMENT: map diff --git a/idea/idea-completion/testData/handlers/basic/typeArgsForCall/FunctionTypeParameter2.kt.after b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/FunctionTypeParameter2.kt.after new file mode 100644 index 00000000000..186bae9f9d3 --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/FunctionTypeParameter2.kt.after @@ -0,0 +1,5 @@ +fun f(list: List) { + list.map { } +} + +// ELEMENT: map diff --git a/idea/idea-completion/testData/handlers/basic/typeArgsForCall/HasExpectedType.kt b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/HasExpectedType.kt new file mode 100644 index 00000000000..df7a31c487f --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/HasExpectedType.kt @@ -0,0 +1,7 @@ +public inline fun Iterable<*>.myFirstIsInstance(): T { } + +fun foo(list: List): String { + return list. +} + +// ELEMENT: myFirstIsInstance diff --git a/idea/idea-completion/testData/handlers/basic/typeArgsForCall/HasExpectedType.kt.after b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/HasExpectedType.kt.after new file mode 100644 index 00000000000..830ad9d3baa --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/HasExpectedType.kt.after @@ -0,0 +1,7 @@ +public inline fun Iterable<*>.myFirstIsInstance(): T { } + +fun foo(list: List): String { + return list.myFirstIsInstance() +} + +// ELEMENT: myFirstIsInstance diff --git a/idea/idea-completion/testData/handlers/basic/typeArgsForCall/NotAllTypeArgumentsFromParameters.kt b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/NotAllTypeArgumentsFromParameters.kt new file mode 100644 index 00000000000..4f1eff673c4 --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/NotAllTypeArgumentsFromParameters.kt @@ -0,0 +1,7 @@ +fun foo(t: T1): T1 {} + +fun f() { + +} + +// ELEMENT: foo diff --git a/idea/idea-completion/testData/handlers/basic/typeArgsForCall/NotAllTypeArgumentsFromParameters.kt.after b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/NotAllTypeArgumentsFromParameters.kt.after new file mode 100644 index 00000000000..a4115552c1d --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/NotAllTypeArgumentsFromParameters.kt.after @@ -0,0 +1,7 @@ +fun foo(t: T1): T1 {} + +fun f() { + foo<>() +} + +// ELEMENT: foo diff --git a/idea/idea-completion/testData/handlers/basic/typeArgsForCall/Simple.kt b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/Simple.kt new file mode 100644 index 00000000000..7e739e75add --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/Simple.kt @@ -0,0 +1,9 @@ +inline fun Iterable<*>.myFilterIsInstance(): List { + return filterIsInstanceTo(ArrayList()) +} + +fun foo(list: List) { + list. +} + +// ELEMENT: myFilterIsInstance diff --git a/idea/idea-completion/testData/handlers/basic/typeArgsForCall/Simple.kt.after b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/Simple.kt.after new file mode 100644 index 00000000000..7d64f30027e --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/Simple.kt.after @@ -0,0 +1,9 @@ +inline fun Iterable<*>.myFilterIsInstance(): List { + return filterIsInstanceTo(ArrayList()) +} + +fun foo(list: List) { + list.myFilterIsInstance<>() +} + +// ELEMENT: myFilterIsInstance diff --git a/idea/idea-completion/testData/handlers/basic/typeArgsForCall/TypeArgumentsFromParameters.kt b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/TypeArgumentsFromParameters.kt new file mode 100644 index 00000000000..b7f139ce0b3 --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/TypeArgumentsFromParameters.kt @@ -0,0 +1,7 @@ +fun T1.foo(t: T2): T2 = t + +fun foo() { + "". +} + +// ELEMENT: foo diff --git a/idea/idea-completion/testData/handlers/basic/typeArgsForCall/TypeArgumentsFromParameters.kt.after b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/TypeArgumentsFromParameters.kt.after new file mode 100644 index 00000000000..70c5864146b --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/typeArgsForCall/TypeArgumentsFromParameters.kt.after @@ -0,0 +1,7 @@ +fun T1.foo(t: T2): T2 = t + +fun foo() { + "".foo() +} + +// ELEMENT: foo diff --git a/idea/idea-completion/testData/handlers/smart/DoNotInsertTypeArguments.kt b/idea/idea-completion/testData/handlers/smart/DoNotInsertTypeArguments.kt new file mode 100644 index 00000000000..97ab1419b83 --- /dev/null +++ b/idea/idea-completion/testData/handlers/smart/DoNotInsertTypeArguments.kt @@ -0,0 +1,7 @@ +public inline fun Iterable<*>.foo(): List { } + +fun f(list: List): Collection { + return list. +} + +// ELEMENT: foo diff --git a/idea/idea-completion/testData/handlers/smart/DoNotInsertTypeArguments.kt.after b/idea/idea-completion/testData/handlers/smart/DoNotInsertTypeArguments.kt.after new file mode 100644 index 00000000000..b084e803a38 --- /dev/null +++ b/idea/idea-completion/testData/handlers/smart/DoNotInsertTypeArguments.kt.after @@ -0,0 +1,7 @@ +public inline fun Iterable<*>.foo(): List { } + +fun f(list: List): Collection { + return list.foo() +} + +// ELEMENT: foo diff --git a/idea/idea-completion/testData/handlers/smart/InsertTypeArguments.kt b/idea/idea-completion/testData/handlers/smart/InsertTypeArguments.kt new file mode 100644 index 00000000000..23214acfb2c --- /dev/null +++ b/idea/idea-completion/testData/handlers/smart/InsertTypeArguments.kt @@ -0,0 +1,7 @@ +public inline fun Iterable<*>.foo(): String { } + +fun f(list: List): String { + return list. +} + +// ELEMENT: foo diff --git a/idea/idea-completion/testData/handlers/smart/InsertTypeArguments.kt.after b/idea/idea-completion/testData/handlers/smart/InsertTypeArguments.kt.after new file mode 100644 index 00000000000..baadd0a9722 --- /dev/null +++ b/idea/idea-completion/testData/handlers/smart/InsertTypeArguments.kt.after @@ -0,0 +1,7 @@ +public inline fun Iterable<*>.foo(): String { } + +fun f(list: List): String { + return list.foo<>() +} + +// ELEMENT: foo diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/BasicCompletionHandlerTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/BasicCompletionHandlerTestGenerated.java index ddba423aacb..95e96a0dd84 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/BasicCompletionHandlerTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/BasicCompletionHandlerTestGenerated.java @@ -400,4 +400,67 @@ public class BasicCompletionHandlerTestGenerated extends AbstractBasicCompletion doTest(fileName); } } + + @TestMetadata("idea/idea-completion/testData/handlers/basic/typeArgsForCall") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class TypeArgsForCall extends AbstractBasicCompletionHandlerTest { + public void testAllFilesPresentInTypeArgsForCall() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/handlers/basic/typeArgsForCall"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("ExpectedTypeDoesNotHelp.kt") + public void testExpectedTypeDoesNotHelp() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/typeArgsForCall/ExpectedTypeDoesNotHelp.kt"); + doTest(fileName); + } + + @TestMetadata("ExpectedTypeDoesNotHelp2.kt") + public void testExpectedTypeDoesNotHelp2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/typeArgsForCall/ExpectedTypeDoesNotHelp2.kt"); + doTest(fileName); + } + + @TestMetadata("ExplicitLambdaSignature.kt") + public void testExplicitLambdaSignature() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/typeArgsForCall/ExplicitLambdaSignature.kt"); + doTest(fileName); + } + + @TestMetadata("FunctionTypeParameter1.kt") + public void testFunctionTypeParameter1() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/typeArgsForCall/FunctionTypeParameter1.kt"); + doTest(fileName); + } + + @TestMetadata("FunctionTypeParameter2.kt") + public void testFunctionTypeParameter2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/typeArgsForCall/FunctionTypeParameter2.kt"); + doTest(fileName); + } + + @TestMetadata("HasExpectedType.kt") + public void testHasExpectedType() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/typeArgsForCall/HasExpectedType.kt"); + doTest(fileName); + } + + @TestMetadata("NotAllTypeArgumentsFromParameters.kt") + public void testNotAllTypeArgumentsFromParameters() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/typeArgsForCall/NotAllTypeArgumentsFromParameters.kt"); + doTest(fileName); + } + + @TestMetadata("Simple.kt") + public void testSimple() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/typeArgsForCall/Simple.kt"); + doTest(fileName); + } + + @TestMetadata("TypeArgumentsFromParameters.kt") + public void testTypeArgumentsFromParameters() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/typeArgsForCall/TypeArgumentsFromParameters.kt"); + doTest(fileName); + } + } } diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/SmartCompletionHandlerTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/SmartCompletionHandlerTestGenerated.java index 8b9475ae3b7..35f63a4f858 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/SmartCompletionHandlerTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/SmartCompletionHandlerTestGenerated.java @@ -311,6 +311,12 @@ public class SmartCompletionHandlerTestGenerated extends AbstractSmartCompletion doTest(fileName); } + @TestMetadata("DoNotInsertTypeArguments.kt") + public void testDoNotInsertTypeArguments() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/DoNotInsertTypeArguments.kt"); + doTest(fileName); + } + @TestMetadata("DoNotReplaceOnEnter.kt") public void testDoNotReplaceOnEnter() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/DoNotReplaceOnEnter.kt"); @@ -413,6 +419,12 @@ public class SmartCompletionHandlerTestGenerated extends AbstractSmartCompletion doTest(fileName); } + @TestMetadata("InsertTypeArguments.kt") + public void testInsertTypeArguments() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/InsertTypeArguments.kt"); + doTest(fileName); + } + @TestMetadata("JavaEnumMemberInsertsImport.kt") public void testJavaEnumMemberInsertsImport() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/JavaEnumMemberInsertsImport.kt");