diff --git a/idea/src/org/jetbrains/kotlin/idea/completion/KotlinCompletionCharFilter.kt b/idea/src/org/jetbrains/kotlin/idea/completion/KotlinCompletionCharFilter.kt index 54f40cd40e5..958a5b3b062 100644 --- a/idea/src/org/jetbrains/kotlin/idea/completion/KotlinCompletionCharFilter.kt +++ b/idea/src/org/jetbrains/kotlin/idea/completion/KotlinCompletionCharFilter.kt @@ -23,6 +23,10 @@ import org.jetbrains.kotlin.psi.JetFile import com.intellij.openapi.util.Key import com.intellij.codeInsight.completion.CompletionService import com.intellij.codeInsight.completion.CompletionProgressIndicator +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.psi.psiUtil.prevLeafSkipWhitespacesAndComments +import org.jetbrains.kotlin.lexer.JetTokens +import org.jetbrains.kotlin.psi.JetFunctionLiteral public class KotlinCompletionCharFilter() : CharFilter() { class object { @@ -36,9 +40,19 @@ public class KotlinCompletionCharFilter() : CharFilter() { if (!lookup.isCompletion()) return null // it does not work in tests, so we use other way // val isAutopopup = CompletionService.getCompletionService().getCurrentCompletion().isAutopopupCompletion() - val isAutopopup = (CompletionService.getCompletionService().getCurrentCompletion() as CompletionProgressIndicator).getParameters().getInvocationCount() == 0 + val completionParameters = (CompletionService.getCompletionService().getCurrentCompletion() as CompletionProgressIndicator).getParameters() + val isAutopopup = completionParameters.getInvocationCount() == 0 - if (Character.isJavaIdentifierPart(c) || c == ':' /* used in '::xxx'*/ || c == '@') { + if (Character.isJavaIdentifierPart(c) || c == '@') { + return CharFilter.Result.ADD_TO_PREFIX + } + + // do not accept items by special chars in the very beginning of function literal where name of the first parameter can be + if (isAutopopup && !lookup.isSelectionTouched() && isInFunctionLiteralStart(completionParameters.getPosition())) { + return Result.HIDE_LOOKUP + } + + if (c == ':' /* used in '::xxx'*/) { return CharFilter.Result.ADD_TO_PREFIX } @@ -70,4 +84,14 @@ public class KotlinCompletionCharFilter() : CharFilter() { else -> CharFilter.Result.HIDE_LOOKUP } } + + private fun isInFunctionLiteralStart(position: PsiElement): Boolean { + var prev = position.prevLeafSkipWhitespacesAndComments() + if (prev?.getNode()?.getElementType() == JetTokens.LPAR) { + prev = prev?.prevLeafSkipWhitespacesAndComments() + } + if (prev?.getNode()?.getElementType() != JetTokens.LBRACE) return false + val functionLiteral = prev!!.getParent() as? JetFunctionLiteral ?: return false + return functionLiteral.getLBrace() == prev + } } diff --git a/idea/src/org/jetbrains/kotlin/idea/completion/KotlinCompletionContributor.kt b/idea/src/org/jetbrains/kotlin/idea/completion/KotlinCompletionContributor.kt index 1cea527f590..82c58056b26 100644 --- a/idea/src/org/jetbrains/kotlin/idea/completion/KotlinCompletionContributor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/completion/KotlinCompletionContributor.kt @@ -248,9 +248,6 @@ public class KotlinCompletionContributor : CompletionContributor() { // no auto-popup on typing after "val", "var" and "fun" because it's likely the name of the declaration which is being typed by user if (invocationCount == 0 && isInExtensionReceiver(position)) return true - // no auto-popup on typing in the very beginning of function literal where name of the first parameter can be - if (invocationCount == 0 && isInFunctionLiteralStart(position)) return true - return false } @@ -267,16 +264,6 @@ public class KotlinCompletionContributor : CompletionContributor() { } } - private fun isInFunctionLiteralStart(position: PsiElement): Boolean { - var prev = position.prevLeafSkipWhitespacesAndComments() - if (prev?.getNode()?.getElementType() == JetTokens.LPAR) { - prev = prev?.prevLeafSkipWhitespacesAndComments() - } - if (prev?.getNode()?.getElementType() != JetTokens.LBRACE) return false - val functionLiteral = prev!!.getParent() as? JetFunctionLiteral ?: return false - return functionLiteral.getLBrace() == prev - } - private fun isAtEndOfLine(offset: Int, document: Document): Boolean { var i = offset val chars = document.getCharsSequence() diff --git a/idea/testData/completion/basic/common/FunctionLiteralParameterName0.kt b/idea/testData/completion/basic/common/FunctionLiteralParameterName0.kt index b2cb76d672f..b0b93eca6fd 100644 --- a/idea/testData/completion/basic/common/FunctionLiteralParameterName0.kt +++ b/idea/testData/completion/basic/common/FunctionLiteralParameterName0.kt @@ -3,4 +3,5 @@ fun bar() { } // INVOCATION_COUNT: 0 -// NUMBER: 0 +// EXIST: bar +// EXIST: null diff --git a/idea/testData/completion/basic/common/FunctionLiteralParameterName1.kt b/idea/testData/completion/basic/common/FunctionLiteralParameterName1.kt index c1a20dbff97..c5121c132de 100644 --- a/idea/testData/completion/basic/common/FunctionLiteralParameterName1.kt +++ b/idea/testData/completion/basic/common/FunctionLiteralParameterName1.kt @@ -3,4 +3,5 @@ fun bar() { } // INVOCATION_COUNT: 0 -// NUMBER: 0 +// EXIST: bar +// EXIST: null diff --git a/idea/testData/completion/basic/common/FunctionLiteralParameterName5.kt b/idea/testData/completion/basic/common/FunctionLiteralParameterName5.kt index 9dd05b3784f..bb9325e7bd4 100644 --- a/idea/testData/completion/basic/common/FunctionLiteralParameterName5.kt +++ b/idea/testData/completion/basic/common/FunctionLiteralParameterName5.kt @@ -5,4 +5,5 @@ fun bar() { } // INVOCATION_COUNT: 0 -// NUMBER: 0 +// EXIST: bar +// EXIST: null diff --git a/idea/testData/completion/handlers/charFilter/FunctionLiteralParameter1.kt b/idea/testData/completion/handlers/charFilter/FunctionLiteralParameter1.kt new file mode 100644 index 00000000000..7a86c3ffa7f --- /dev/null +++ b/idea/testData/completion/handlers/charFilter/FunctionLiteralParameter1.kt @@ -0,0 +1,9 @@ +fun foo(p: (String) -> Unit){} + +fun bar() { + foo { p } +} + +// INVOCATION_COUNT: 0 +// ELEMENT: * +// CHAR: ' ' diff --git a/idea/testData/completion/handlers/charFilter/FunctionLiteralParameter1.kt.after b/idea/testData/completion/handlers/charFilter/FunctionLiteralParameter1.kt.after new file mode 100644 index 00000000000..cb982fcbeb3 --- /dev/null +++ b/idea/testData/completion/handlers/charFilter/FunctionLiteralParameter1.kt.after @@ -0,0 +1,9 @@ +fun foo(p: (String) -> Unit){} + +fun bar() { + foo { p } +} + +// INVOCATION_COUNT: 0 +// ELEMENT: * +// CHAR: ' ' diff --git a/idea/testData/completion/handlers/charFilter/FunctionLiteralParameter2.kt b/idea/testData/completion/handlers/charFilter/FunctionLiteralParameter2.kt new file mode 100644 index 00000000000..8109f7efb27 --- /dev/null +++ b/idea/testData/completion/handlers/charFilter/FunctionLiteralParameter2.kt @@ -0,0 +1,9 @@ +fun foo(p: (String) -> Unit){} + +fun bar() { + foo { (p } +} + +// INVOCATION_COUNT: 0 +// ELEMENT: * +// CHAR: ':' diff --git a/idea/testData/completion/handlers/charFilter/FunctionLiteralParameter2.kt.after b/idea/testData/completion/handlers/charFilter/FunctionLiteralParameter2.kt.after new file mode 100644 index 00000000000..3506ccff39f --- /dev/null +++ b/idea/testData/completion/handlers/charFilter/FunctionLiteralParameter2.kt.after @@ -0,0 +1,9 @@ +fun foo(p: (String) -> Unit){} + +fun bar() { + foo { (p: } +} + +// INVOCATION_COUNT: 0 +// ELEMENT: * +// CHAR: ':' diff --git a/idea/testData/completion/handlers/charFilter/FunctionLiteralParameter3.kt b/idea/testData/completion/handlers/charFilter/FunctionLiteralParameter3.kt new file mode 100644 index 00000000000..62b20d5f77f --- /dev/null +++ b/idea/testData/completion/handlers/charFilter/FunctionLiteralParameter3.kt @@ -0,0 +1,9 @@ +fun bar() { + val handler = { p + foo() + } +} + +// INVOCATION_COUNT: 0 +// ELEMENT: * +// CHAR: ' ' diff --git a/idea/testData/completion/handlers/charFilter/FunctionLiteralParameter3.kt.after b/idea/testData/completion/handlers/charFilter/FunctionLiteralParameter3.kt.after new file mode 100644 index 00000000000..6c43bd91f06 --- /dev/null +++ b/idea/testData/completion/handlers/charFilter/FunctionLiteralParameter3.kt.after @@ -0,0 +1,9 @@ +fun bar() { + val handler = { p + foo() + } +} + +// INVOCATION_COUNT: 0 +// ELEMENT: * +// CHAR: ' ' diff --git a/idea/tests/org/jetbrains/kotlin/completion/handlers/CompletionCharFilterTestGenerated.java b/idea/tests/org/jetbrains/kotlin/completion/handlers/CompletionCharFilterTestGenerated.java index 48c7d616219..1172fa252ae 100644 --- a/idea/tests/org/jetbrains/kotlin/completion/handlers/CompletionCharFilterTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/completion/handlers/CompletionCharFilterTestGenerated.java @@ -126,6 +126,24 @@ public class CompletionCharFilterTestGenerated extends AbstractCompletionCharFil doTest(fileName); } + @TestMetadata("FunctionLiteralParameter1.kt") + public void testFunctionLiteralParameter1() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/handlers/charFilter/FunctionLiteralParameter1.kt"); + doTest(fileName); + } + + @TestMetadata("FunctionLiteralParameter2.kt") + public void testFunctionLiteralParameter2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/handlers/charFilter/FunctionLiteralParameter2.kt"); + doTest(fileName); + } + + @TestMetadata("FunctionLiteralParameter3.kt") + public void testFunctionLiteralParameter3() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/handlers/charFilter/FunctionLiteralParameter3.kt"); + doTest(fileName); + } + @TestMetadata("FunctionWithLambdaArg1.kt") public void testFunctionWithLambdaArg1() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/completion/handlers/charFilter/FunctionWithLambdaArg1.kt");