diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicLookupElementFactory.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicLookupElementFactory.kt index 6742290b0bc..d510e18864d 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicLookupElementFactory.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/BasicLookupElementFactory.kt @@ -191,41 +191,7 @@ class BasicLookupElementFactory( } if (descriptor is CallableDescriptor) { - val extensionReceiver = descriptor.original.extensionReceiverParameter - when { - descriptor is SyntheticJavaPropertyDescriptor -> { - var from = descriptor.getMethod.getName().asString() + "()" - descriptor.setMethod?.let { from += "/" + it.getName().asString() + "()" } - element = element.appendTailText(" (from $from)", true) - } - - // no need to show them as extensions - descriptor is SamAdapterExtensionFunctionDescriptor -> {} - - extensionReceiver != null -> { - val receiverPresentation = DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(extensionReceiver.type) - element = element.appendTailText(" for $receiverPresentation", true) - - val container = descriptor.getContainingDeclaration() - val containerPresentation = if (container is ClassDescriptor) - DescriptorUtils.getFqNameFromTopLevelClass(container).toString() - else if (container is PackageFragmentDescriptor) - container.fqName.toString() - else - null - if (containerPresentation != null) { - element = element.appendTailText(" in $containerPresentation", true) - } - } - - else -> { - val container = descriptor.getContainingDeclaration() - if (container is PackageFragmentDescriptor) { // we show container only for global functions and properties - //TODO: it would be probably better to show it also for static declarations which are not from the current class (imported) - element = element.appendTailText(" (${container.fqName})", true) - } - } - } + appendContainerAndReceiverInformation(descriptor) { tail, grayed -> element = element.appendTailText(tail, grayed) } } if (descriptor is PropertyDescriptor) { @@ -249,6 +215,46 @@ class BasicLookupElementFactory( return element.withIconFromLookupObject() } + public fun appendContainerAndReceiverInformation(descriptor: CallableDescriptor, appendTailText: (String, Boolean) -> Unit) { + val extensionReceiver = descriptor.original.extensionReceiverParameter + when { + descriptor is SyntheticJavaPropertyDescriptor -> { + var from = descriptor.getMethod.getName().asString() + "()" + descriptor.setMethod?.let { from += "/" + it.getName().asString() + "()" } + appendTailText(" (from $from)", true) + } + + // no need to show them as extensions + descriptor is SamAdapterExtensionFunctionDescriptor -> { + } + + extensionReceiver != null -> { + val receiverPresentation = DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(extensionReceiver.type) + appendTailText(" for $receiverPresentation", true) + + val container = descriptor.getContainingDeclaration() + val containerPresentation = if (container is ClassDescriptor) + DescriptorUtils.getFqNameFromTopLevelClass(container).toString() + else if (container is PackageFragmentDescriptor) + container.fqName.toString() + else + null + if (containerPresentation != null) { + appendTailText(" in $containerPresentation", true) + } + } + + else -> { + val container = descriptor.getContainingDeclaration() + if (container is PackageFragmentDescriptor) { + // we show container only for global functions and properties + //TODO: it would be probably better to show it also for static declarations which are not from the current class (imported) + appendTailText(" (${container.fqName})", true) + } + } + } + } + private fun LookupElement.withIconFromLookupObject(): LookupElement { // add icon in renderElement only to pass presentation.isReal() return object : LookupElementDecorator(this) { 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 2bb27ce77c2..1232df08a4a 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 @@ -140,14 +140,14 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC protected val receiversData: ReferenceVariantsHelper.ReceiversData? = nameExpression?.let { referenceVariantsHelper.getReferenceVariantsReceivers(it) } - private val factoryContext = if (expression?.getParent() is JetSimpleNameStringTemplateEntry) - LookupElementFactory.Context.STRING_TEMPLATE_AFTER_DOLLAR - else if (receiversData?.callType == CallType.INFIX) - LookupElementFactory.Context.INFIX_CALL - else - LookupElementFactory.Context.NORMAL - protected val lookupElementFactory: LookupElementFactory = run { + val contextType = if (expression?.getParent() is JetSimpleNameStringTemplateEntry) + LookupElementFactory.ContextType.STRING_TEMPLATE_AFTER_DOLLAR + else if (receiversData?.callType == CallType.INFIX) + LookupElementFactory.ContextType.INFIX_CALL + else + LookupElementFactory.ContextType.NORMAL + var receiverTypes = emptyList() if (receiversData != null) { val dataFlowInfo = bindingContext.getDataFlowInfo(expression) @@ -168,7 +168,14 @@ abstract class CompletionSession(protected val configuration: CompletionSessionC } } - LookupElementFactory(resolutionFacade, receiverTypes, factoryContext, inDescriptor, InsertHandlerProvider { expectedInfos }) + val contextVariablesProvider = { + nameExpression?.let { + referenceVariantsHelper.getReferenceVariants(it, DescriptorKindFilter.VARIABLES, { true }, explicitReceiverData = null) + .map { it as VariableDescriptor } + } ?: emptyList() + } + + LookupElementFactory(resolutionFacade, receiverTypes, contextType, inDescriptor, InsertHandlerProvider { expectedInfos }, contextVariablesProvider) } // LookupElementsCollector instantiation is deferred because virtual call to createSorter uses data from derived classes 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 25970f00cfe..237f0a3187c 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 @@ -30,6 +30,8 @@ import org.jetbrains.kotlin.idea.completion.handlers.GenerateLambdaInfo import org.jetbrains.kotlin.idea.completion.handlers.KotlinFunctionInsertHandler import org.jetbrains.kotlin.idea.completion.handlers.buildLambdaPresentation import org.jetbrains.kotlin.idea.resolve.ResolutionFacade +import org.jetbrains.kotlin.idea.util.FuzzyType +import org.jetbrains.kotlin.idea.util.fuzzyReturnType import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.JetProperty import org.jetbrains.kotlin.resolve.BindingContext @@ -45,13 +47,18 @@ import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf class LookupElementFactory( private val resolutionFacade: ResolutionFacade, private val receiverTypes: Collection, - private val context: LookupElementFactory.Context, + private val contextType: LookupElementFactory.ContextType, private val inDescriptor: DeclarationDescriptor?, - public val insertHandlerProvider: InsertHandlerProvider + public val insertHandlerProvider: InsertHandlerProvider, + contextVariablesProvider: () -> Collection ) { private val basicFactory = BasicLookupElementFactory(resolutionFacade.project, insertHandlerProvider) - public enum class Context { + private val functionTypeContextVariables by lazy { + contextVariablesProvider().filter { KotlinBuiltIns.isFunctionOrExtensionFunctionType(it.type) } + } + + public enum class ContextType { NORMAL, STRING_TEMPLATE_AFTER_DOLLAR, INFIX_CALL @@ -61,20 +68,20 @@ class LookupElementFactory( val result = SmartList() var lookupElement = createLookupElement(descriptor, useReceiverTypes) - if (context == Context.STRING_TEMPLATE_AFTER_DOLLAR && (descriptor is FunctionDescriptor || descriptor is ClassifierDescriptor)) { + if (contextType == ContextType.STRING_TEMPLATE_AFTER_DOLLAR && (descriptor is FunctionDescriptor || descriptor is ClassifierDescriptor)) { lookupElement = lookupElement.withBracesSurrounding() } result.add(lookupElement) // add special item for function with one argument of function type with more than one parameter - if (context != Context.INFIX_CALL && descriptor is FunctionDescriptor) { + if (contextType != ContextType.INFIX_CALL && descriptor is FunctionDescriptor) { result.addSpecialFunctionCallElements(descriptor, useReceiverTypes) } if (descriptor is PropertyDescriptor && inDescriptor != null) { var backingFieldElement = createBackingFieldLookupElement(descriptor, useReceiverTypes) if (backingFieldElement != null) { - if (context == Context.STRING_TEMPLATE_AFTER_DOLLAR) { + if (contextType == ContextType.STRING_TEMPLATE_AFTER_DOLLAR) { backingFieldElement = backingFieldElement.withBracesSurrounding() } result.add(backingFieldElement) @@ -92,6 +99,17 @@ class LookupElementFactory( if (functionParameterCount > 1) { add(createFunctionCallElementWithExplicitLambdaParameters(descriptor, parameterType, useReceiverTypes)) } + + //TODO: also ::function? at least for local functions + //TODO: order for them + val fuzzyParameterType = FuzzyType(parameterType, descriptor.typeParameters) + for (variable in functionTypeContextVariables) { + val substitutor = variable.fuzzyReturnType()?.checkIsSubtypeOf(fuzzyParameterType) + if (substitutor != null) { + val substitutedDescriptor = descriptor.substitute(substitutor) ?: continue + add(createFunctionCallElementWithArgument(substitutedDescriptor, variable.name.asString(), useReceiverTypes)) + } + } } } @@ -115,13 +133,49 @@ class LookupElementFactory( } } - if (context == Context.STRING_TEMPLATE_AFTER_DOLLAR) { + if (contextType == ContextType.STRING_TEMPLATE_AFTER_DOLLAR) { lookupElement = lookupElement.withBracesSurrounding() } return lookupElement } + private fun createFunctionCallElementWithArgument(descriptor: FunctionDescriptor, argumentText: String, useReceiverTypes: Boolean): LookupElement { + var lookupElement = createLookupElement(descriptor, useReceiverTypes) + + val needTypeArguments = (insertHandlerProvider.insertHandler(descriptor) as KotlinFunctionInsertHandler).needTypeArguments + lookupElement = FunctionCallWithArgumentLookupElement(lookupElement, descriptor, argumentText, needTypeArguments) + + if (contextType == ContextType.STRING_TEMPLATE_AFTER_DOLLAR) { + lookupElement = lookupElement.withBracesSurrounding() + } + + return lookupElement + } + + private inner class FunctionCallWithArgumentLookupElement( + originalLookupElement: LookupElement, + private val descriptor: FunctionDescriptor, + private val argumentText: String, + private val needTypeArguments: Boolean + ) : LookupElementDecorator(originalLookupElement) { + + override fun equals(other: Any?) = other is FunctionCallWithArgumentLookupElement && delegate == other.delegate && argumentText == other.argumentText + override fun hashCode() = delegate.hashCode() * 17 + argumentText.hashCode() + + override fun renderElement(presentation: LookupElementPresentation) { + super.renderElement(presentation) + + presentation.clearTail() + presentation.appendTailText("($argumentText)", false) + basicFactory.appendContainerAndReceiverInformation(descriptor) { tail, grayed -> presentation.appendTailText(tail, grayed) } + } + + override fun handleInsert(context: InsertionContext) { + KotlinFunctionInsertHandler(needTypeArguments = needTypeArguments, needValueArguments = false, argumentText = argumentText).handleInsert(context, this) + } + } + private fun createBackingFieldLookupElement(property: PropertyDescriptor, useReceiverTypes: Boolean): LookupElement? { if (inDescriptor == null) return null val insideAccessor = inDescriptor is PropertyAccessorDescriptor && inDescriptor.getCorrespondingProperty() == property 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 880e884d875..b5c7e48a758 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,14 +35,21 @@ import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.types.JetType -data class GenerateLambdaInfo(val lambdaType: JetType, val explicitParameters: Boolean) +class GenerateLambdaInfo(val lambdaType: JetType, val explicitParameters: Boolean) class KotlinFunctionInsertHandler( val needTypeArguments: Boolean, val needValueArguments: Boolean, + val argumentText: String = "", val lambdaInfo: GenerateLambdaInfo? = null ) : KotlinCallableInsertHandler() { + init { + if (lambdaInfo != null) { + assert(argumentText == "") + } + } + public override fun handleInsert(context: InsertionContext, item: LookupElement) { super.handleInsert(context, item) @@ -66,7 +73,7 @@ class KotlinFunctionInsertHandler( context.getEditor().getCaretModel().moveToOffset(tailOffset + 1) } - else -> addBrackets(context, element) + else -> addArguments(context, element) } } @@ -76,7 +83,7 @@ class KotlinFunctionInsertHandler( return parent is JetSimpleNameExpression && grandParent is JetBinaryExpression && parent == grandParent.getOperationReference() } - private fun addBrackets(context : InsertionContext, offsetElement : PsiElement) { + private fun addArguments(context : InsertionContext, offsetElement : PsiElement) { val completionChar = context.getCompletionChar() if (completionChar == '(') { //TODO: more correct behavior related to braces type context.setAddCompletionChar(false) @@ -153,6 +160,11 @@ class KotlinFunctionInsertHandler( closeBracketOffset = chars.indexOfSkippingSpace(closingBracket, openingBracketOffset + 1)!! } + document.insertString(openingBracketOffset + 1, argumentText) + if (closeBracketOffset != null) { + closeBracketOffset += argumentText.length() + } + if (!insertTypeArguments) { if (shouldPlaceCaretInBrackets(completionChar) || closeBracketOffset == null) { editor.caretModel.moveToOffset(openingBracketOffset + 1 + inBracketsShift) diff --git a/idea/idea-completion/testData/basic/common/highOrderFunctions/ContextVariables1.kt b/idea/idea-completion/testData/basic/common/highOrderFunctions/ContextVariables1.kt new file mode 100644 index 00000000000..d8891297797 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/highOrderFunctions/ContextVariables1.kt @@ -0,0 +1,30 @@ +interface I : () -> Unit + +fun xfoo(p: () -> Unit){} + +val global: () -> Unit = { } + +fun X.test(p1: () -> Unit, p2: () -> String, p3: I) { + val local: () -> Unit = { } + xfoo +} + +interface X { + public val publicVal: () -> Unit + protected val protectedVal: () -> Unit +} + +val X.extension: () -> Unit + get() = {} + +val String.wrongExtension: () -> Unit + get() = {} + +// EXIST: { itemText: "xfoo", tailText: " {...} (p: () -> Unit) ()", typeText:"Unit" } +// EXIST: { itemText: "xfoo", tailText: "(p1) ()", typeText: "Unit" } +// EXIST: { itemText: "xfoo", tailText: "(p3) ()", typeText: "Unit" } +// EXIST: { itemText: "xfoo", tailText: "(local) ()", typeText: "Unit" } +// EXIST: { itemText: "xfoo", tailText: "(global) ()", typeText: "Unit" } +// EXIST: { itemText: "xfoo", tailText: "(publicVal) ()", typeText: "Unit" } +// EXIST: { itemText: "xfoo", tailText: "(extension) ()", typeText: "Unit" } +// NOTHING_ELSE diff --git a/idea/idea-completion/testData/basic/common/highOrderFunctions/ContextVariables2.kt b/idea/idea-completion/testData/basic/common/highOrderFunctions/ContextVariables2.kt new file mode 100644 index 00000000000..4ace842af9b --- /dev/null +++ b/idea/idea-completion/testData/basic/common/highOrderFunctions/ContextVariables2.kt @@ -0,0 +1,30 @@ +interface I : () -> Unit + +fun String.xfoo(p: () -> Unit){} + +val global: () -> Unit = { } + +fun X.test(p1: () -> Unit, p2: () -> String, p3: I) { + val local: () -> Unit = { } + "a".xfoo +} + +interface X { + public val publicVal: () -> Unit + protected val protectedVal: () -> Unit +} + +val X.extension: () -> Unit + get() = {} + +val String.wrongExtension: () -> Unit + get() = {} + +// EXIST: { itemText: "xfoo", tailText: " {...} (p: () -> Unit) for String in ", typeText:"Unit" } +// EXIST: { itemText: "xfoo", tailText: "(p1) for String in ", typeText: "Unit" } +// EXIST: { itemText: "xfoo", tailText: "(p3) for String in ", typeText: "Unit" } +// EXIST: { itemText: "xfoo", tailText: "(local) for String in ", typeText: "Unit" } +// EXIST: { itemText: "xfoo", tailText: "(global) for String in ", typeText: "Unit" } +// EXIST: { itemText: "xfoo", tailText: "(publicVal) for String in ", typeText: "Unit" } +// EXIST: { itemText: "xfoo", tailText: "(extension) for String in ", typeText: "Unit" } +// NOTHING_ELSE diff --git a/idea/idea-completion/testData/basic/common/highOrderFunctions/ContextVariablesFilter.kt b/idea/idea-completion/testData/basic/common/highOrderFunctions/ContextVariablesFilter.kt new file mode 100644 index 00000000000..576d20cb4c3 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/highOrderFunctions/ContextVariablesFilter.kt @@ -0,0 +1,7 @@ +fun test(p1: (String) -> Boolean, p2: (Int) -> Boolean) { + listOf("a", "b").filt +} + +// EXIST: { itemText: "filter", tailText: " {...} (predicate: (String) -> Boolean) for Iterable in kotlin", typeText:"List" } +// EXIST: { itemText: "filter", tailText: "(p1) for Iterable in kotlin", typeText: "List" } +// ABSENT: { itemText: "filter", tailText: "(p2) for Iterable in kotlin", typeText: "List" } diff --git a/idea/idea-completion/testData/basic/common/highOrderFunctions/ContextVariablesMap.kt b/idea/idea-completion/testData/basic/common/highOrderFunctions/ContextVariablesMap.kt new file mode 100644 index 00000000000..0ad76c81200 --- /dev/null +++ b/idea/idea-completion/testData/basic/common/highOrderFunctions/ContextVariablesMap.kt @@ -0,0 +1,8 @@ +fun test(p1: (String) -> Int, p2: (Int) -> Int, p3: (String) -> Char) { + listOf("a", "b").map +} + +// EXIST: { itemText: "map", tailText: " {...} (transform: (String) -> R) for Iterable in kotlin", typeText:"List" } +// EXIST: { itemText: "map", tailText: "(p1) for Iterable in kotlin", typeText: "List" } +// ABSENT: { itemText: "map", tailText: "(p2) for Iterable in kotlin", typeText: "List" } +// EXIST: { itemText: "map", tailText: "(p3) for Iterable in kotlin", typeText: "List" } diff --git a/idea/idea-completion/testData/basic/common/highOrderFunctions/ContextVariablesShadowing.kt b/idea/idea-completion/testData/basic/common/highOrderFunctions/ContextVariablesShadowing.kt new file mode 100644 index 00000000000..3823ce6a98a --- /dev/null +++ b/idea/idea-completion/testData/basic/common/highOrderFunctions/ContextVariablesShadowing.kt @@ -0,0 +1,24 @@ +interface I1 { + val v: () -> Unit + val v1: () -> Unit +} + +interface I2 { + val v: String +} + +fun String.xfoo(p: () -> Unit){} + +fun X.test(i1: I1, i2: I2) { + with(i1) { + with(i2) { + "a".xfoo + } + } +} + +interface X + +// EXIST: { itemText: "xfoo", tailText: " {...} (p: () -> Unit) for String in ", typeText:"Unit" } +// EXIST: { itemText: "xfoo", tailText: "(v1) for String in ", typeText: "Unit" } +// NOTHING_ELSE diff --git a/idea/idea-completion/testData/basic/common/HigherOrderFunction1.kt b/idea/idea-completion/testData/basic/common/highOrderFunctions/HigherOrderFunction1.kt similarity index 95% rename from idea/idea-completion/testData/basic/common/HigherOrderFunction1.kt rename to idea/idea-completion/testData/basic/common/highOrderFunctions/HigherOrderFunction1.kt index b1294efbb1a..023d6eefede 100644 --- a/idea/idea-completion/testData/basic/common/HigherOrderFunction1.kt +++ b/idea/idea-completion/testData/basic/common/highOrderFunctions/HigherOrderFunction1.kt @@ -1,7 +1,7 @@ fun foo(p: (String, Char) -> Unit){} fun test() { - fo + foo } // EXIST: { lookupString:"foo", itemText: "foo", tailText: "(p: (String, Char) -> Unit) ()", typeText:"Unit" } diff --git a/idea/idea-completion/testData/basic/common/HigherOrderFunction2.kt b/idea/idea-completion/testData/basic/common/highOrderFunctions/HigherOrderFunction2.kt similarity index 100% rename from idea/idea-completion/testData/basic/common/HigherOrderFunction2.kt rename to idea/idea-completion/testData/basic/common/highOrderFunctions/HigherOrderFunction2.kt diff --git a/idea/idea-completion/testData/handlers/basic/highOrderFunctions/ContextVariable.kt b/idea/idea-completion/testData/handlers/basic/highOrderFunctions/ContextVariable.kt new file mode 100644 index 00000000000..cb98510bfc3 --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/highOrderFunctions/ContextVariable.kt @@ -0,0 +1,9 @@ +fun String.xfoo(p: () -> Unit){} + +fun X.test() { + val local: () -> Unit = { } + "a".xf +} + +// ELEMENT: xfoo +// TAIL_TEXT: "(local) for String in " diff --git a/idea/idea-completion/testData/handlers/basic/highOrderFunctions/ContextVariable.kt.after b/idea/idea-completion/testData/handlers/basic/highOrderFunctions/ContextVariable.kt.after new file mode 100644 index 00000000000..a26c5b91887 --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/highOrderFunctions/ContextVariable.kt.after @@ -0,0 +1,9 @@ +fun String.xfoo(p: () -> Unit){} + +fun X.test() { + val local: () -> Unit = { } + "a".xfoo(local) +} + +// ELEMENT: xfoo +// TAIL_TEXT: "(local) for String in " diff --git a/idea/idea-completion/testData/handlers/basic/highOrderFunctions/ContextVariableDot.kt b/idea/idea-completion/testData/handlers/basic/highOrderFunctions/ContextVariableDot.kt new file mode 100644 index 00000000000..dac22452a59 --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/highOrderFunctions/ContextVariableDot.kt @@ -0,0 +1,10 @@ +fun String.xfoo(p: () -> Unit): String = "" + +fun X.test() { + val local: () -> Unit = { } + "a".xf +} + +// ELEMENT: xfoo +// TAIL_TEXT: "(local) for String in " +// CHAR: '.' diff --git a/idea/idea-completion/testData/handlers/basic/highOrderFunctions/ContextVariableDot.kt.after b/idea/idea-completion/testData/handlers/basic/highOrderFunctions/ContextVariableDot.kt.after new file mode 100644 index 00000000000..22ad011ccf0 --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/highOrderFunctions/ContextVariableDot.kt.after @@ -0,0 +1,10 @@ +fun String.xfoo(p: () -> Unit): String = "" + +fun X.test() { + val local: () -> Unit = { } + "a".xfoo(local). +} + +// ELEMENT: xfoo +// TAIL_TEXT: "(local) for String in " +// CHAR: '.' diff --git a/idea/idea-completion/testData/handlers/basic/highOrderFunctions/ContextVariableTypeArgsNeeded.kt b/idea/idea-completion/testData/handlers/basic/highOrderFunctions/ContextVariableTypeArgsNeeded.kt new file mode 100644 index 00000000000..9801c852af7 --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/highOrderFunctions/ContextVariableTypeArgsNeeded.kt @@ -0,0 +1,9 @@ +inline fun String.xfoo(p: () -> Unit){} + +fun X.test() { + val local: () -> Unit = { } + "a".xf +} + +// ELEMENT: xfoo +// TAIL_TEXT: "(local) for String in " diff --git a/idea/idea-completion/testData/handlers/basic/highOrderFunctions/ContextVariableTypeArgsNeeded.kt.after b/idea/idea-completion/testData/handlers/basic/highOrderFunctions/ContextVariableTypeArgsNeeded.kt.after new file mode 100644 index 00000000000..97e615b9b6a --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/highOrderFunctions/ContextVariableTypeArgsNeeded.kt.after @@ -0,0 +1,9 @@ +inline fun String.xfoo(p: () -> Unit){} + +fun X.test() { + val local: () -> Unit = { } + "a".xfoo<>(local) +} + +// ELEMENT: xfoo +// TAIL_TEXT: "(local) for String in " diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java index 3b3a21103a0..c349dcc760e 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JSBasicCompletionTestGenerated.java @@ -217,18 +217,6 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes doTest(fileName); } - @TestMetadata("HigherOrderFunction1.kt") - public void testHigherOrderFunction1() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/HigherOrderFunction1.kt"); - doTest(fileName); - } - - @TestMetadata("HigherOrderFunction2.kt") - public void testHigherOrderFunction2() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/HigherOrderFunction2.kt"); - doTest(fileName); - } - @TestMetadata("ImportedEnumMembers.kt") public void testImportedEnumMembers() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/ImportedEnumMembers.kt"); @@ -1327,6 +1315,57 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes } } + @TestMetadata("idea/idea-completion/testData/basic/common/highOrderFunctions") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class HighOrderFunctions extends AbstractJSBasicCompletionTest { + public void testAllFilesPresentInHighOrderFunctions() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/basic/common/highOrderFunctions"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("ContextVariables1.kt") + public void testContextVariables1() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/highOrderFunctions/ContextVariables1.kt"); + doTest(fileName); + } + + @TestMetadata("ContextVariables2.kt") + public void testContextVariables2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/highOrderFunctions/ContextVariables2.kt"); + doTest(fileName); + } + + @TestMetadata("ContextVariablesFilter.kt") + public void testContextVariablesFilter() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/highOrderFunctions/ContextVariablesFilter.kt"); + doTest(fileName); + } + + @TestMetadata("ContextVariablesMap.kt") + public void testContextVariablesMap() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/highOrderFunctions/ContextVariablesMap.kt"); + doTest(fileName); + } + + @TestMetadata("ContextVariablesShadowing.kt") + public void testContextVariablesShadowing() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/highOrderFunctions/ContextVariablesShadowing.kt"); + doTest(fileName); + } + + @TestMetadata("HigherOrderFunction1.kt") + public void testHigherOrderFunction1() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/highOrderFunctions/HigherOrderFunction1.kt"); + doTest(fileName); + } + + @TestMetadata("HigherOrderFunction2.kt") + public void testHigherOrderFunction2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/highOrderFunctions/HigherOrderFunction2.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/idea-completion/testData/basic/common/lambdaSignature") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java index dd2cf726df2..128331c0796 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java @@ -217,18 +217,6 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT doTest(fileName); } - @TestMetadata("HigherOrderFunction1.kt") - public void testHigherOrderFunction1() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/HigherOrderFunction1.kt"); - doTest(fileName); - } - - @TestMetadata("HigherOrderFunction2.kt") - public void testHigherOrderFunction2() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/HigherOrderFunction2.kt"); - doTest(fileName); - } - @TestMetadata("ImportedEnumMembers.kt") public void testImportedEnumMembers() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/ImportedEnumMembers.kt"); @@ -1327,6 +1315,57 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT } } + @TestMetadata("idea/idea-completion/testData/basic/common/highOrderFunctions") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class HighOrderFunctions extends AbstractJvmBasicCompletionTest { + public void testAllFilesPresentInHighOrderFunctions() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/basic/common/highOrderFunctions"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("ContextVariables1.kt") + public void testContextVariables1() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/highOrderFunctions/ContextVariables1.kt"); + doTest(fileName); + } + + @TestMetadata("ContextVariables2.kt") + public void testContextVariables2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/highOrderFunctions/ContextVariables2.kt"); + doTest(fileName); + } + + @TestMetadata("ContextVariablesFilter.kt") + public void testContextVariablesFilter() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/highOrderFunctions/ContextVariablesFilter.kt"); + doTest(fileName); + } + + @TestMetadata("ContextVariablesMap.kt") + public void testContextVariablesMap() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/highOrderFunctions/ContextVariablesMap.kt"); + doTest(fileName); + } + + @TestMetadata("ContextVariablesShadowing.kt") + public void testContextVariablesShadowing() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/highOrderFunctions/ContextVariablesShadowing.kt"); + doTest(fileName); + } + + @TestMetadata("HigherOrderFunction1.kt") + public void testHigherOrderFunction1() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/highOrderFunctions/HigherOrderFunction1.kt"); + doTest(fileName); + } + + @TestMetadata("HigherOrderFunction2.kt") + public void testHigherOrderFunction2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/basic/common/highOrderFunctions/HigherOrderFunction2.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/idea-completion/testData/basic/common/lambdaSignature") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) 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 95e96a0dd84..0a74bfd05fe 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 @@ -202,6 +202,24 @@ public class BasicCompletionHandlerTestGenerated extends AbstractBasicCompletion JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/idea-completion/testData/handlers/basic/highOrderFunctions"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("ContextVariable.kt") + public void testContextVariable() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/highOrderFunctions/ContextVariable.kt"); + doTest(fileName); + } + + @TestMetadata("ContextVariableDot.kt") + public void testContextVariableDot() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/highOrderFunctions/ContextVariableDot.kt"); + doTest(fileName); + } + + @TestMetadata("ContextVariableTypeArgsNeeded.kt") + public void testContextVariableTypeArgsNeeded() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/highOrderFunctions/ContextVariableTypeArgsNeeded.kt"); + doTest(fileName); + } + @TestMetadata("ForceParenthesisForTabChar.kt") public void testForceParenthesisForTabChar() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/highOrderFunctions/ForceParenthesisForTabChar.kt");