diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ExpectedInfos.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ExpectedInfos.kt index 59b1dd0ebdb..9613e0b5017 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ExpectedInfos.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/ExpectedInfos.kt @@ -208,11 +208,21 @@ class ExpectedInfos( } } else { + val lastNonOptionalParam = parameters.lastOrNull { !it.hasDefaultValue() } + + fun needCommaForParameter(parameter: ValueParameterDescriptor): Boolean { + if (parameter.hasDefaultValue()) return false // parameter is optional + if (parameter.getVarargElementType() != null) return false // vararg arguments list can be empty + // last non-optional parameter of functional type can be placed outside parenthesis: + if (parameter == lastNonOptionalParam && KotlinBuiltIns.isFunctionOrExtensionFunctionType(parameter.getType())) return false + return true + } + val tail = if (isFunctionLiteralArgument) null else if (parameterIndex == parameters.lastIndex) Tail.RPARENTH //TODO: support square brackets - else if (parameters.drop(parameterIndex + 1).all { it.hasDefaultValue() || it.getVarargElementType() != null }) + else if (parameters.drop(parameterIndex + 1).none(::needCommaForParameter)) null else Tail.COMMA diff --git a/idea/idea-completion/testData/handlers/smart/FunctionLiteralParamAlreadyExist.kt b/idea/idea-completion/testData/handlers/smart/FunctionLiteralParamAlreadyExist.kt new file mode 100644 index 00000000000..9dcd3bc75cc --- /dev/null +++ b/idea/idea-completion/testData/handlers/smart/FunctionLiteralParamAlreadyExist.kt @@ -0,0 +1,7 @@ +fun foo(p: Int, handler: () -> Unit){} + +fun bar(p: Int) { + foo() { doIt() } +} + +// ELEMENT: p diff --git a/idea/idea-completion/testData/handlers/smart/FunctionLiteralParamAlreadyExist.kt.after b/idea/idea-completion/testData/handlers/smart/FunctionLiteralParamAlreadyExist.kt.after new file mode 100644 index 00000000000..6ecdad1ac4a --- /dev/null +++ b/idea/idea-completion/testData/handlers/smart/FunctionLiteralParamAlreadyExist.kt.after @@ -0,0 +1,7 @@ +fun foo(p: Int, handler: () -> Unit){} + +fun bar(p: Int) { + foo(p) { doIt() } +} + +// ELEMENT: p diff --git a/idea/idea-completion/testData/handlers/smart/LastNonOptionalParamIsFunction.kt b/idea/idea-completion/testData/handlers/smart/LastNonOptionalParamIsFunction.kt new file mode 100644 index 00000000000..b55af545f3b --- /dev/null +++ b/idea/idea-completion/testData/handlers/smart/LastNonOptionalParamIsFunction.kt @@ -0,0 +1,7 @@ +fun foo(p: Int, handler: () -> Unit, optional: String = ""){} + +fun bar(p: Int) { + foo() +} + +// ELEMENT: p diff --git a/idea/idea-completion/testData/handlers/smart/LastNonOptionalParamIsFunction.kt.after b/idea/idea-completion/testData/handlers/smart/LastNonOptionalParamIsFunction.kt.after new file mode 100644 index 00000000000..72a6b758102 --- /dev/null +++ b/idea/idea-completion/testData/handlers/smart/LastNonOptionalParamIsFunction.kt.after @@ -0,0 +1,7 @@ +fun foo(p: Int, handler: () -> Unit, optional: String = ""){} + +fun bar(p: Int) { + foo(p) +} + +// ELEMENT: p 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 0ae77c99690..6f89a86ffa4 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 @@ -329,6 +329,12 @@ public class SmartCompletionHandlerTestGenerated extends AbstractSmartCompletion doTest(fileName); } + @TestMetadata("FunctionLiteralParamAlreadyExist.kt") + public void testFunctionLiteralParamAlreadyExist() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/FunctionLiteralParamAlreadyExist.kt"); + doTest(fileName); + } + @TestMetadata("FunctionReference1.kt") public void testFunctionReference1() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/FunctionReference1.kt"); @@ -461,6 +467,12 @@ public class SmartCompletionHandlerTestGenerated extends AbstractSmartCompletion doTest(fileName); } + @TestMetadata("LastNonOptionalParamIsFunction.kt") + public void testLastNonOptionalParamIsFunction() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/LastNonOptionalParamIsFunction.kt"); + doTest(fileName); + } + @TestMetadata("MergeTail1.kt") public void testMergeTail1() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/MergeTail1.kt");