From c2065c185617c92fe856c848b372e916ca2b78ab Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Sat, 23 Jan 2016 00:57:42 +0300 Subject: [PATCH] "contains" now requires to be marked as operator + no heuristic signature for contains needed anymore --- .../smart/inOperator/ExtensionContains.kt | 3 ++- .../smart/inOperator/FilterByArgumentType.kt | 6 ++--- .../smart/inOperator/GenericMethod2.kt | 2 +- .../smart/inOperator/GenericMethod3.kt | 2 +- .../smart/inOperator/NonBooleanContains.kt | 2 +- .../kotlin/idea/core/ExpectedInfos.kt | 2 +- .../idea/core/TypesWithContainsDetector.kt | 23 +++++++------------ 7 files changed, 17 insertions(+), 23 deletions(-) diff --git a/idea/idea-completion/testData/smart/inOperator/ExtensionContains.kt b/idea/idea-completion/testData/smart/inOperator/ExtensionContains.kt index 72ea56f584b..4254d18e84a 100644 --- a/idea/idea-completion/testData/smart/inOperator/ExtensionContains.kt +++ b/idea/idea-completion/testData/smart/inOperator/ExtensionContains.kt @@ -2,7 +2,8 @@ interface X interface Y : X interface Z -fun X.contains(s: String): Boolean +operator fun X.contains(s: String): Boolean = true +fun Z.contains(s: String): Boolean = true fun foo(s: String, x: X, y: Y, z: Z) { if (s in ) diff --git a/idea/idea-completion/testData/smart/inOperator/FilterByArgumentType.kt b/idea/idea-completion/testData/smart/inOperator/FilterByArgumentType.kt index 0f4c52c18c2..33e4622de3c 100644 --- a/idea/idea-completion/testData/smart/inOperator/FilterByArgumentType.kt +++ b/idea/idea-completion/testData/smart/inOperator/FilterByArgumentType.kt @@ -1,13 +1,13 @@ interface X { - fun contains(s: String): Boolean + operator fun contains(s: String): Boolean } interface Y { - fun contains(i: Int): Boolean + operator fun contains(i: Int): Boolean } interface Z { - fun contains(o: Any): Boolean + operator fun contains(o: Any): Boolean } fun foo(s: String, x: X, y: Y, z: Z) { diff --git a/idea/idea-completion/testData/smart/inOperator/GenericMethod2.kt b/idea/idea-completion/testData/smart/inOperator/GenericMethod2.kt index 40959add9cc..3aac6350a8f 100644 --- a/idea/idea-completion/testData/smart/inOperator/GenericMethod2.kt +++ b/idea/idea-completion/testData/smart/inOperator/GenericMethod2.kt @@ -1,5 +1,5 @@ interface X { - fun contains(t: T): Boolean + operator fun contains(t: T): Boolean } interface A { diff --git a/idea/idea-completion/testData/smart/inOperator/GenericMethod3.kt b/idea/idea-completion/testData/smart/inOperator/GenericMethod3.kt index 227c5543730..38880de94f1 100644 --- a/idea/idea-completion/testData/smart/inOperator/GenericMethod3.kt +++ b/idea/idea-completion/testData/smart/inOperator/GenericMethod3.kt @@ -1,6 +1,6 @@ interface X -fun X.contains(t: T): Boolean +operator fun X.contains(t: T): Boolean = true interface A { fun createX(t: T): X diff --git a/idea/idea-completion/testData/smart/inOperator/NonBooleanContains.kt b/idea/idea-completion/testData/smart/inOperator/NonBooleanContains.kt index 10e38f3a8df..a8dd36f88f2 100644 --- a/idea/idea-completion/testData/smart/inOperator/NonBooleanContains.kt +++ b/idea/idea-completion/testData/smart/inOperator/NonBooleanContains.kt @@ -1,5 +1,5 @@ interface X { - fun contains(s: String): Boolean? + operator fun contains(s: String): Boolean? } fun foo(s: String, x: X) { diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/ExpectedInfos.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/ExpectedInfos.kt index bc249bc657c..6cd4e8f722f 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/ExpectedInfos.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/ExpectedInfos.kt @@ -586,7 +586,7 @@ class ExpectedInfos( val leftOperandType = binaryExpression.left?.let { bindingContext.getType(it) } ?: return null val scope = expressionWithType.getResolutionScope(bindingContext, resolutionFacade) - val detector = TypesWithContainsDetector(scope, leftOperandType, resolutionFacade) + val detector = TypesWithContainsDetector(scope, leftOperandType) val byTypeFilter = object : ByTypeFilter { override fun matchingSubstitutor(descriptorType: FuzzyType): TypeSubstitutor? { diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/TypesWithContainsDetector.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/TypesWithContainsDetector.kt index 4dca38f1d92..c9ccdd478ba 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/TypesWithContainsDetector.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/TypesWithContainsDetector.kt @@ -18,31 +18,25 @@ package org.jetbrains.kotlin.idea.core import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor -import org.jetbrains.kotlin.idea.resolve.ResolutionFacade -import org.jetbrains.kotlin.idea.resolve.ideService import org.jetbrains.kotlin.idea.util.FuzzyType import org.jetbrains.kotlin.idea.util.nullability import org.jetbrains.kotlin.incremental.components.NoLookupLocation -import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.resolve.scopes.utils.collectFunctions import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.typeUtil.TypeNullability +import org.jetbrains.kotlin.util.OperatorNameConventions +import org.jetbrains.kotlin.util.isValidOperator import java.util.* internal class TypesWithContainsDetector( private val scope: LexicalScope, - private val argumentType: KotlinType, - private val resolutionFacade: ResolutionFacade + private val argumentType: KotlinType ) { private val cache = HashMap() - private val containsName = Name.identifier("contains") - private val booleanType = resolutionFacade.moduleDescriptor.builtIns.booleanType - private val heuristicSignatures = resolutionFacade.ideService() private val typesWithExtensionContains: Collection = scope - .collectFunctions(containsName, NoLookupLocation.FROM_IDE) + .collectFunctions(OperatorNameConventions.CONTAINS, NoLookupLocation.FROM_IDE) .filter { it.extensionReceiverParameter != null && isGoodContainsFunction(it, listOf()) } .map { it.extensionReceiverParameter!!.type } @@ -52,15 +46,14 @@ internal class TypesWithContainsDetector( private fun hasContainsNoCache(type: FuzzyType): Boolean { return type.nullability() != TypeNullability.NULLABLE && - type.type.memberScope.getContributedFunctions(containsName, NoLookupLocation.FROM_IDE).any { isGoodContainsFunction(it, type.freeParameters) } + type.type.memberScope.getContributedFunctions(OperatorNameConventions.CONTAINS, NoLookupLocation.FROM_IDE).any { isGoodContainsFunction(it, type.freeParameters) } || typesWithExtensionContains.any { type.checkIsSubtypeOf(it) != null } } private fun isGoodContainsFunction(function: FunctionDescriptor, freeTypeParams: Collection): Boolean { - if (!TypeUtils.equalTypes(function.returnType!!, booleanType)) return false - val parameter = function.valueParameters.singleOrNull() ?: return false - val parameterType = heuristicSignatures.correctedParameterType(function, parameter) ?: parameter.type - val fuzzyParameterType = FuzzyType(parameterType, function.typeParameters + freeTypeParams) + if (!function.isValidOperator()) return false + val parameter = function.valueParameters.single() + val fuzzyParameterType = FuzzyType(parameter.type, function.typeParameters + freeTypeParams) return fuzzyParameterType.checkIsSuperTypeOf(argumentType) != null } }