diff --git a/idea/src/org/jetbrains/jet/plugin/completion/ExpectedInfos.kt b/idea/src/org/jetbrains/jet/plugin/completion/ExpectedInfos.kt index 3f54fe3dbb4..b975537776a 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/ExpectedInfos.kt +++ b/idea/src/org/jetbrains/jet/plugin/completion/ExpectedInfos.kt @@ -50,7 +50,6 @@ import org.jetbrains.jet.lang.resolve.calls.util.DelegatingCall import org.jetbrains.jet.lang.resolve.calls.util.noErrorsInValueArguments import org.jetbrains.jet.lang.resolve.calls.util.hasUnmappedParameters import org.jetbrains.jet.lang.descriptors.Visibilities -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptorWithVisibility enum class Tail { COMMA @@ -66,6 +65,7 @@ class ExpectedInfos(val bindingContext: BindingContext, val moduleDescriptor: Mo ?: calculateForFunctionLiteralArgument(expressionWithType) ?: calculateForEq(expressionWithType) ?: calculateForIf(expressionWithType) + ?: calculateForElvis(expressionWithType) ?: getFromBindingContext(expressionWithType) } @@ -186,6 +186,28 @@ class ExpectedInfos(val bindingContext: BindingContext, val moduleDescriptor: Mo } } + private fun calculateForElvis(expressionWithType: JetExpression): Collection? { + val binaryExpression = expressionWithType.getParent() as? JetBinaryExpression + if (binaryExpression != null) { + val operationToken = binaryExpression.getOperationToken() + if (operationToken == JetTokens.ELVIS && expressionWithType == binaryExpression.getRight()) { + val otherOperand = binaryExpression.getLeft() ?: return null + val otherOperandType = bindingContext[BindingContext.EXPRESSION_TYPE, otherOperand] + val expectedInfos = calculate(binaryExpression) + if (expectedInfos != null) { + return if (otherOperandType != null) + expectedInfos.filter { it.`type`.isSubtypeOf(otherOperandType) } + else + expectedInfos + } + else if (otherOperandType != null) { + return listOf(ExpectedInfo(TypeUtils.makeNotNullable(otherOperandType), null)) + } + } + } + return null + } + private fun getFromBindingContext(expressionWithType: JetExpression): Collection? { val expectedType = bindingContext[BindingContext.EXPECTED_EXPRESSION_TYPE, expressionWithType] ?: return null return listOf(ExpectedInfo(expectedType, null)) diff --git a/idea/testData/completion/handlers/smart/InElvisOperator.kt b/idea/testData/completion/handlers/smart/InElvisOperator.kt new file mode 100644 index 00000000000..1062564b53b --- /dev/null +++ b/idea/testData/completion/handlers/smart/InElvisOperator.kt @@ -0,0 +1,7 @@ +fun foo(s: String, c: Char){} + +fun bar(p1: String?, p2: String) { + foo(p1 ?: +} + +// ELEMENT: p2 diff --git a/idea/testData/completion/handlers/smart/InElvisOperator.kt.after b/idea/testData/completion/handlers/smart/InElvisOperator.kt.after new file mode 100644 index 00000000000..9785c95357d --- /dev/null +++ b/idea/testData/completion/handlers/smart/InElvisOperator.kt.after @@ -0,0 +1,7 @@ +fun foo(s: String, c: Char){} + +fun bar(p1: String?, p2: String) { + foo(p1 ?: p2, +} + +// ELEMENT: p2 diff --git a/idea/testData/completion/smart/InElvisOperator1.kt b/idea/testData/completion/smart/InElvisOperator1.kt new file mode 100644 index 00000000000..2e8c43c9709 --- /dev/null +++ b/idea/testData/completion/smart/InElvisOperator1.kt @@ -0,0 +1,9 @@ +fun foo(p: String?){} +fun foo(p: Char){} + +fun bar(p1: String?, p2: String?, p3: Char) { + foo(p1 ?: +} + +// EXIST: { itemText:"p2" } +// ABSENT: p3 diff --git a/idea/testData/completion/smart/InElvisOperator2.kt b/idea/testData/completion/smart/InElvisOperator2.kt new file mode 100644 index 00000000000..0ac6283556b --- /dev/null +++ b/idea/testData/completion/smart/InElvisOperator2.kt @@ -0,0 +1,12 @@ +fun foo1(): String? = null +fun foo2(): String? = null +fun foo3(): String = "" + +fun bar() { + foo1() ?: +} + +// EXIST: { itemText:"foo3()" } +// ABSENT: { itemText:"foo2()" } +// EXIST: { itemText:"!! foo2()" } +// EXIST: { itemText:"?: foo2()" } diff --git a/idea/tests/org/jetbrains/jet/completion/JvmSmartCompletionTestGenerated.java b/idea/tests/org/jetbrains/jet/completion/JvmSmartCompletionTestGenerated.java index 7019469b2c5..f56e9a104a5 100644 --- a/idea/tests/org/jetbrains/jet/completion/JvmSmartCompletionTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/completion/JvmSmartCompletionTestGenerated.java @@ -216,6 +216,16 @@ public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT doTest("idea/testData/completion/smart/IfValue3.kt"); } + @TestMetadata("InElvisOperator1.kt") + public void testInElvisOperator1() throws Exception { + doTest("idea/testData/completion/smart/InElvisOperator1.kt"); + } + + @TestMetadata("InElvisOperator2.kt") + public void testInElvisOperator2() throws Exception { + doTest("idea/testData/completion/smart/InElvisOperator2.kt"); + } + @TestMetadata("InaccessibleConstructor.kt") public void testInaccessibleConstructor() throws Exception { doTest("idea/testData/completion/smart/InaccessibleConstructor.kt"); diff --git a/idea/tests/org/jetbrains/jet/completion/handlers/SmartCompletionHandlerTestGenerated.java b/idea/tests/org/jetbrains/jet/completion/handlers/SmartCompletionHandlerTestGenerated.java index 2a73bf3ef1b..cd25eac0aa2 100644 --- a/idea/tests/org/jetbrains/jet/completion/handlers/SmartCompletionHandlerTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/completion/handlers/SmartCompletionHandlerTestGenerated.java @@ -226,6 +226,11 @@ public class SmartCompletionHandlerTestGenerated extends AbstractSmartCompletion doTest("idea/testData/completion/handlers/smart/IfValue3.kt"); } + @TestMetadata("InElvisOperator.kt") + public void testInElvisOperator() throws Exception { + doTest("idea/testData/completion/handlers/smart/InElvisOperator.kt"); + } + @TestMetadata("JavaEnumMemberInsertsImport.kt") public void testJavaEnumMemberInsertsImport() throws Exception { doTest("idea/testData/completion/handlers/smart/JavaEnumMemberInsertsImport.kt");