x?.y != null and x?.call() != null provoke now x != null, a set of tests #KT-2127 Fixed

This commit is contained in:
Mikhail Glukhikh
2016-07-19 11:17:16 +03:00
committed by Mikhail Glukhikh
parent 9001b9bcc0
commit 11f50186fa
11 changed files with 249 additions and 32 deletions
@@ -180,10 +180,11 @@ object DataFlowValueFactory {
is KtQualifiedExpression -> {
val receiverExpression = expression.receiverExpression
val selectorExpression = expression.selectorExpression
val receiverId = getIdForStableIdentifier(receiverExpression, bindingContext, containingDeclarationOrModule)
val selectorId = getIdForStableIdentifier(selectorExpression, bindingContext, containingDeclarationOrModule)
val receiverInfo = getIdForStableIdentifier(receiverExpression, bindingContext, containingDeclarationOrModule)
val selectorInfo = getIdForStableIdentifier(selectorExpression, bindingContext, containingDeclarationOrModule)
IdentifierInfo.qualified(receiverId, selectorId, expression.operationSign === KtTokens.SAFE_ACCESS)
IdentifierInfo.qualified(receiverInfo, bindingContext.getType(receiverExpression),
selectorInfo, expression.operationSign === KtTokens.SAFE_ACCESS)
}
is KtSimpleNameExpression ->
getIdForSimpleNameExpression(expression, bindingContext, containingDeclarationOrModule)
@@ -219,13 +220,25 @@ object DataFlowValueFactory {
// for now it fails for resolving 'invoke' convention, return it after 'invoke' algorithm changes
// assert resolvedCall != null : "Cannot create right identifier info if the resolved call is not known yet for
val usageModuleDescriptor = DescriptorUtils.getContainingModuleOrNull(containingDeclarationOrModule)
val receiverInfo = resolvedCall?.let { getIdForImplicitReceiver(it.dispatchReceiver, simpleNameExpression) }
val selectorInfo = IdentifierInfo.Variable(declarationDescriptor,
variableKind(declarationDescriptor, usageModuleDescriptor,
bindingContext, simpleNameExpression))
IdentifierInfo.qualified(receiverInfo,
IdentifierInfo.Variable(declarationDescriptor,
variableKind(declarationDescriptor, usageModuleDescriptor,
bindingContext, simpleNameExpression)),
resolvedCall?.call?.isSafeCall() ?: false)
val implicitReceiver = resolvedCall?.dispatchReceiver
if (implicitReceiver == null) {
selectorInfo
}
else {
val receiverInfo = getIdForImplicitReceiver(implicitReceiver, simpleNameExpression)
if (receiverInfo == null) {
selectorInfo
}
else {
IdentifierInfo.qualified(receiverInfo, implicitReceiver.type,
selectorInfo, resolvedCall?.call?.isSafeCall() ?: false)
}
}
}
is PackageViewDescriptor, is ClassDescriptor -> IdentifierInfo.PackageOrClass(declarationDescriptor)
else -> IdentifierInfo.NO
@@ -90,8 +90,18 @@ internal class DelegatingDataFlowInfo private constructor(
}
}
private fun putNullability(map: MutableMap<DataFlowValue, Nullability>, value: DataFlowValue, nullability: Nullability): Boolean {
private fun putNullability(map: MutableMap<DataFlowValue, Nullability>, value: DataFlowValue,
nullability: Nullability, affectReceiver: Boolean = true): Boolean {
map.put(value, nullability)
val identifierInfo = value.identifierInfo
if (affectReceiver && !nullability.canBeNull() && identifierInfo is IdentifierInfo.Qualified) {
val receiverType = identifierInfo.receiverType
if (identifierInfo.safe && receiverType != null) {
putNullability(map, DataFlowValue(identifierInfo.receiverInfo, receiverType), nullability)
}
}
return nullability != getCollectedNullability(value)
}
@@ -135,7 +145,7 @@ internal class DelegatingDataFlowInfo private constructor(
override fun assign(a: DataFlowValue, b: DataFlowValue): DataFlowInfo {
val nullability = Maps.newHashMap<DataFlowValue, Nullability>()
val nullabilityOfB = getPredictableNullability(b)
putNullability(nullability, a, nullabilityOfB)
putNullability(nullability, a, nullabilityOfB, affectReceiver = false)
val newTypeInfo = newTypeInfo()
var typesForB = getPredictableTypes(b)
@@ -212,7 +222,7 @@ internal class DelegatingDataFlowInfo private constructor(
val nullabilityOfA = getPredictableNullability(a)
val nullabilityOfB = getPredictableNullability(b)
var changed = putNullability(builder, a, nullabilityOfA.refine(nullabilityOfB.invert())) or
val changed = putNullability(builder, a, nullabilityOfA.refine(nullabilityOfB.invert())) or
putNullability(builder, b, nullabilityOfB.refine(nullabilityOfA.invert()))
return if (changed) create(this, ImmutableMap.copyOf(builder), EMPTY_TYPE_INFO) else this
}