"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 Y : X
interface Z 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) { fun foo(s: String, x: X, y: Y, z: Z) {
if (s in <caret>) if (s in <caret>)
@@ -1,13 +1,13 @@
interface X { interface X {
fun contains(s: String): Boolean operator fun contains(s: String): Boolean
} }
interface Y { interface Y {
fun contains(i: Int): Boolean operator fun contains(i: Int): Boolean
} }
interface Z { interface Z {
fun contains(o: Any): Boolean operator fun contains(o: Any): Boolean
} }
fun foo(s: String, x: X, y: Y, z: Z) { fun foo(s: String, x: X, y: Y, z: Z) {
@@ -1,5 +1,5 @@
interface X<T> { interface X<T> {
fun contains(t: T): Boolean operator fun contains(t: T): Boolean
} }
interface A { interface A {
@@ -1,6 +1,6 @@
interface X<T> interface X<T>
fun<T> X<T>.contains(t: T): Boolean operator fun<T> X<T>.contains(t: T): Boolean = true
interface A { interface A {
fun<T> createX(t: T): X<T> fun<T> createX(t: T): X<T>
@@ -1,5 +1,5 @@
interface X { interface X {
fun contains(s: String): Boolean? operator fun contains(s: String): Boolean?
} }
fun foo(s: String, x: X) { fun foo(s: String, x: X) {
@@ -586,7 +586,7 @@ class ExpectedInfos(
val leftOperandType = binaryExpression.left?.let { bindingContext.getType(it) } ?: return null val leftOperandType = binaryExpression.left?.let { bindingContext.getType(it) } ?: return null
val scope = expressionWithType.getResolutionScope(bindingContext, resolutionFacade) val scope = expressionWithType.getResolutionScope(bindingContext, resolutionFacade)
val detector = TypesWithContainsDetector(scope, leftOperandType, resolutionFacade) val detector = TypesWithContainsDetector(scope, leftOperandType)
val byTypeFilter = object : ByTypeFilter { val byTypeFilter = object : ByTypeFilter {
override fun matchingSubstitutor(descriptorType: FuzzyType): TypeSubstitutor? { 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.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor 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.FuzzyType
import org.jetbrains.kotlin.idea.util.nullability import org.jetbrains.kotlin.idea.util.nullability
import org.jetbrains.kotlin.incremental.components.NoLookupLocation 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.LexicalScope
import org.jetbrains.kotlin.resolve.scopes.utils.collectFunctions import org.jetbrains.kotlin.resolve.scopes.utils.collectFunctions
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.typeUtil.TypeNullability import org.jetbrains.kotlin.types.typeUtil.TypeNullability
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.util.isValidOperator
import java.util.* import java.util.*
internal class TypesWithContainsDetector( internal class TypesWithContainsDetector(
private val scope: LexicalScope, private val scope: LexicalScope,
private val argumentType: KotlinType, private val argumentType: KotlinType
private val resolutionFacade: ResolutionFacade
) { ) {
private val cache = HashMap<FuzzyType, Boolean>() 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 private val typesWithExtensionContains: Collection<KotlinType> = scope
.collectFunctions(containsName, NoLookupLocation.FROM_IDE) .collectFunctions(OperatorNameConventions.CONTAINS, NoLookupLocation.FROM_IDE)
.filter { it.extensionReceiverParameter != null && isGoodContainsFunction(it, listOf()) } .filter { it.extensionReceiverParameter != null && isGoodContainsFunction(it, listOf()) }
.map { it.extensionReceiverParameter!!.type } .map { it.extensionReceiverParameter!!.type }
@@ -52,15 +46,14 @@ internal class TypesWithContainsDetector(
private fun hasContainsNoCache(type: FuzzyType): Boolean { private fun hasContainsNoCache(type: FuzzyType): Boolean {
return type.nullability() != TypeNullability.NULLABLE && 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 } || typesWithExtensionContains.any { type.checkIsSubtypeOf(it) != null }
} }
private fun isGoodContainsFunction(function: FunctionDescriptor, freeTypeParams: Collection<TypeParameterDescriptor>): Boolean { private fun isGoodContainsFunction(function: FunctionDescriptor, freeTypeParams: Collection<TypeParameterDescriptor>): Boolean {
if (!TypeUtils.equalTypes(function.returnType!!, booleanType)) return false if (!function.isValidOperator()) return false
val parameter = function.valueParameters.singleOrNull() ?: return false val parameter = function.valueParameters.single()
val parameterType = heuristicSignatures.correctedParameterType(function, parameter) ?: parameter.type val fuzzyParameterType = FuzzyType(parameter.type, function.typeParameters + freeTypeParams)
val fuzzyParameterType = FuzzyType(parameterType, function.typeParameters + freeTypeParams)
return fuzzyParameterType.checkIsSuperTypeOf(argumentType) != null return fuzzyParameterType.checkIsSuperTypeOf(argumentType) != null
} }
} }