"contains" now requires to be marked as operator + no heuristic signature for contains needed anymore

This commit is contained in:
Valentin Kipyatkov
2016-01-23 00:57:42 +03:00
parent 1b9c6e0ea2
commit c2065c1856
7 changed files with 17 additions and 23 deletions
@@ -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 <caret>)
@@ -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) {
@@ -1,5 +1,5 @@
interface X<T> {
fun contains(t: T): Boolean
operator fun contains(t: T): Boolean
}
interface A {
@@ -1,6 +1,6 @@
interface X<T>
fun<T> X<T>.contains(t: T): Boolean
operator fun<T> X<T>.contains(t: T): Boolean = true
interface A {
fun<T> createX(t: T): X<T>
@@ -1,5 +1,5 @@
interface X {
fun contains(s: String): Boolean?
operator fun contains(s: String): Boolean?
}
fun foo(s: String, x: X) {
@@ -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? {
@@ -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<FuzzyType, Boolean>()
private val containsName = Name.identifier("contains")
private val booleanType = resolutionFacade.moduleDescriptor.builtIns.booleanType
private val heuristicSignatures = resolutionFacade.ideService<HeuristicSignatures>()
private val typesWithExtensionContains: Collection<KotlinType> = 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<TypeParameterDescriptor>): 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
}
}