KT-12150 Smart completion suggests to compare non-nullable with null

#KT-12150 Fixed
This commit is contained in:
Valentin Kipyatkov
2016-04-29 17:05:05 +03:00
parent 40900b0050
commit 941b415981
6 changed files with 30 additions and 12 deletions
@@ -26,10 +26,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference
import org.jetbrains.kotlin.idea.completion.smart.ExpectedInfoMatch import org.jetbrains.kotlin.idea.completion.smart.ExpectedInfoMatch
import org.jetbrains.kotlin.idea.completion.smart.SmartCompletionItemPriority import org.jetbrains.kotlin.idea.completion.smart.SmartCompletionItemPriority
import org.jetbrains.kotlin.idea.completion.smart.matchExpectedInfo import org.jetbrains.kotlin.idea.completion.smart.matchExpectedInfo
import org.jetbrains.kotlin.idea.core.ExpectedInfo import org.jetbrains.kotlin.idea.core.*
import org.jetbrains.kotlin.idea.core.IfConditionAdditionalData
import org.jetbrains.kotlin.idea.core.WhenEntryAdditionalData
import org.jetbrains.kotlin.idea.core.fuzzyType
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver
import org.jetbrains.kotlin.idea.util.toFuzzyType import org.jetbrains.kotlin.idea.util.toFuzzyType
@@ -83,10 +80,13 @@ object KeywordValues {
} }
val nullMatcher = { info: ExpectedInfo -> val nullMatcher = { info: ExpectedInfo ->
if (info.fuzzyType != null && info.fuzzyType!!.type.isMarkedNullable) when {
ExpectedInfoMatch.match(TypeSubstitutor.EMPTY) (info.additionalData as? ComparisonOperandAdditionalData)?.suppressNullLiteral == true -> ExpectedInfoMatch.noMatch
else
ExpectedInfoMatch.noMatch info.fuzzyType?.type?.isMarkedNullable == true -> ExpectedInfoMatch.match(TypeSubstitutor.EMPTY)
else -> ExpectedInfoMatch.noMatch
}
} }
consumer.consume("null", nullMatcher, SmartCompletionItemPriority.NULL) { consumer.consume("null", nullMatcher, SmartCompletionItemPriority.NULL) {
LookupElementBuilder.create(KeywordLookupObject(), "null").bold() LookupElementBuilder.create(KeywordLookupObject(), "null").bold()
+1 -1
View File
@@ -11,7 +11,7 @@ fun f(e1: E, e2: E?, x: Any) {
// EXIST: { itemText:"e2" } // EXIST: { itemText:"e2" }
// EXIST: { lookupString:"A", itemText:"E.A", typeText:"E" } // EXIST: { lookupString:"A", itemText:"E.A", typeText:"E" }
// EXIST: { lookupString:"B", itemText:"E.B", typeText:"E" } // EXIST: { lookupString:"B", itemText:"E.B", typeText:"E" }
// EXIST: null // ABSENT: null
// ABSENT: { itemText:"!! e2" } // ABSENT: { itemText:"!! e2" }
// ABSENT: e1 // ABSENT: e1
// ABSENT: x // ABSENT: x
@@ -0,0 +1,7 @@
import java.io.File
fun foo(file: File) {
if (file.name == <caret>)
}
// EXIST: null
+2 -1
View File
@@ -3,12 +3,13 @@ enum class E {
B B
} }
fun f(e1: E, e2: E?, x: Any) { fun f(e1: E?, e2: E, x: Any) {
if (e1 != <caret> if (e1 != <caret>
} }
// EXIST: { lookupString:"A", itemText:"E.A" } // EXIST: { lookupString:"A", itemText:"E.A" }
// EXIST: { lookupString:"B", itemText:"E.B" } // EXIST: { lookupString:"B", itemText:"E.B" }
// EXIST: e2 // EXIST: e2
// EXIST: null
// ABSENT: e1 // ABSENT: e1
// ABSENT: x // ABSENT: x
@@ -137,6 +137,12 @@ public class JvmSmartCompletionTestGenerated extends AbstractJvmSmartCompletionT
doTest(fileName); doTest(fileName);
} }
@TestMetadata("EqOperatorPlatformType.kt")
public void testEqOperatorPlatformType() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/EqOperatorPlatformType.kt");
doTest(fileName);
}
@TestMetadata("ExtensionFunctionTypeVariables.kt") @TestMetadata("ExtensionFunctionTypeVariables.kt")
public void testExtensionFunctionTypeVariables() throws Exception { public void testExtensionFunctionTypeVariables() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/ExtensionFunctionTypeVariables.kt"); String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/smart/ExtensionFunctionTypeVariables.kt");
@@ -148,6 +148,8 @@ object IfConditionAdditionalData : ExpectedInfo.AdditionalData
object PropertyDelegateAdditionalData : ExpectedInfo.AdditionalData object PropertyDelegateAdditionalData : ExpectedInfo.AdditionalData
class ComparisonOperandAdditionalData(val suppressNullLiteral: Boolean) : ExpectedInfo.AdditionalData
class ExpectedInfos( class ExpectedInfos(
private val bindingContext: BindingContext, private val bindingContext: BindingContext,
private val resolutionFacade: ResolutionFacade, private val resolutionFacade: ResolutionFacade,
@@ -414,12 +416,14 @@ class ExpectedInfos(
return listOf(ExpectedInfo(NullableTypesFilter, expectedName, null)) return listOf(ExpectedInfo(NullableTypesFilter, expectedName, null))
} }
// if we complete argument of == or !=, make types in expected info's nullable to allow nullable items too var additionalData: ExpectedInfo.AdditionalData? = null
if (operationToken in COMPARISON_TOKENS) { if (operationToken in COMPARISON_TOKENS) {
// if we complete argument of == or !=, make types in expected info's nullable to allow items of nullable type too
additionalData = ComparisonOperandAdditionalData(suppressNullLiteral = expectedType.nullability() == TypeNullability.NOT_NULL)
expectedType = expectedType.makeNullable() expectedType = expectedType.makeNullable()
} }
return listOf(ExpectedInfo(expectedType, expectedName, null)) return listOf(ExpectedInfo(expectedType, expectedName, null, additionalData = additionalData))
} }
} }
} }