Data flow values refactoring: removed DataFlowValue.kind.isStable, renamed DataFlowValue.isPredictable -> DataFlowValue.isStable
This commit is contained in:
@@ -319,7 +319,7 @@ class CallExpressionResolver(
|
||||
var initialDataFlowInfoForArguments = context.dataFlowInfo
|
||||
val receiverDataFlowValue = (receiver as? ReceiverValue)?.let { DataFlowValueFactory.createDataFlowValue(it, context) }
|
||||
val receiverCanBeNull = receiverDataFlowValue != null &&
|
||||
initialDataFlowInfoForArguments.getPredictableNullability(receiverDataFlowValue).canBeNull()
|
||||
initialDataFlowInfoForArguments.getStableNullability(receiverDataFlowValue).canBeNull()
|
||||
if (receiverDataFlowValue != null && element.safe) {
|
||||
// Additional "receiver != null" information should be applied if we consider a safe call
|
||||
if (receiverCanBeNull) {
|
||||
|
||||
@@ -506,7 +506,7 @@ class CandidateResolver(
|
||||
val outerCallReceiver = call.outerCall.explicitReceiver
|
||||
if (outerCallReceiver != call.explicitReceiver && outerCallReceiver is ReceiverValue) {
|
||||
val outerReceiverDataFlowValue = DataFlowValueFactory.createDataFlowValue(outerCallReceiver, this)
|
||||
val outerReceiverNullability = dataFlowInfo.getPredictableNullability(outerReceiverDataFlowValue)
|
||||
val outerReceiverNullability = dataFlowInfo.getStableNullability(outerReceiverDataFlowValue)
|
||||
if (outerReceiverNullability.canBeNull() && !TypeUtils.isNullableType(expectedReceiverParameterType)) {
|
||||
nullableImplicitInvokeReceiver = true
|
||||
receiverArgumentType = TypeUtils.makeNullable(receiverArgumentType)
|
||||
@@ -515,7 +515,7 @@ class CandidateResolver(
|
||||
}
|
||||
|
||||
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiverArgument, this)
|
||||
val nullability = dataFlowInfo.getPredictableNullability(dataFlowValue)
|
||||
val nullability = dataFlowInfo.getStableNullability(dataFlowValue)
|
||||
val expression = (receiverArgument as? ExpressionReceiver)?.expression
|
||||
if (nullability.canBeNull() && !nullability.canBeNonNull()) {
|
||||
if (!TypeUtils.isNullableType(expectedReceiverParameterType)) {
|
||||
|
||||
+1
-1
@@ -195,7 +195,7 @@ class GenericCandidateResolver(private val argumentTypeResolver: ArgumentTypeRes
|
||||
if (deparenthesizedArgument == null || type == null) return type
|
||||
|
||||
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(deparenthesizedArgument, type, context)
|
||||
if (!dataFlowValue.isPredictable) return type
|
||||
if (!dataFlowValue.isStable) return type
|
||||
|
||||
val possibleTypes = context.dataFlowInfo.getCollectedTypes(dataFlowValue)
|
||||
if (possibleTypes.isEmpty()) return type
|
||||
|
||||
@@ -82,7 +82,7 @@ private fun ResolvedCall<*>.hasSafeNullableReceiver(context: CallResolutionConte
|
||||
if (!call.isSafeCall()) return false
|
||||
val receiverValue = getExplicitReceiverValue()?.let { DataFlowValueFactory.createDataFlowValue(it, context) }
|
||||
?: return false
|
||||
return context.dataFlowInfo.getPredictableNullability(receiverValue).canBeNull()
|
||||
return context.dataFlowInfo.getStableNullability(receiverValue).canBeNull()
|
||||
}
|
||||
|
||||
fun ResolvedCall<*>.makeNullableTypeIfSafeReceiver(type: KotlinType?, context: CallResolutionContext<*>) =
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve.calls.smartcasts
|
||||
|
||||
import com.google.common.collect.ImmutableMap
|
||||
import com.google.common.collect.SetMultimap
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
@@ -31,18 +30,18 @@ interface DataFlowInfo {
|
||||
val completeTypeInfo: SetMultimap<DataFlowValue, KotlinType>
|
||||
|
||||
/**
|
||||
* Returns collected nullability for the given value, NOT taking its predictability into account.
|
||||
* Returns collected nullability for the given value, NOT taking its stability into account.
|
||||
*/
|
||||
fun getCollectedNullability(key: DataFlowValue): Nullability
|
||||
|
||||
/**
|
||||
* Returns collected nullability for the given value if it's predictable.
|
||||
* Returns collected nullability for the given value if it's stable.
|
||||
* Otherwise basic value nullability is returned
|
||||
*/
|
||||
fun getPredictableNullability(key: DataFlowValue): Nullability
|
||||
fun getStableNullability(key: DataFlowValue): Nullability
|
||||
|
||||
/**
|
||||
* Returns possible types for the given value, NOT taking its predictability into account.
|
||||
* Returns possible types for the given value, NOT taking its stability into account.
|
||||
*
|
||||
* IMPORTANT: by default, the original (native) type for this value
|
||||
* are NOT included. So it's quite possible to get an empty set here.
|
||||
@@ -50,13 +49,13 @@ interface DataFlowInfo {
|
||||
fun getCollectedTypes(key: DataFlowValue): Set<KotlinType>
|
||||
|
||||
/**
|
||||
* Returns possible types for the given value if it's predictable.
|
||||
* Returns possible types for the given value if it's stable.
|
||||
* Otherwise, basic value type is returned.
|
||||
*
|
||||
* IMPORTANT: by default, the original (native) type for this value
|
||||
* are NOT included. So it's quite possible to get an empty set here.
|
||||
*/
|
||||
fun getPredictableTypes(key: DataFlowValue): Set<KotlinType>
|
||||
fun getStableTypes(key: DataFlowValue): Set<KotlinType>
|
||||
|
||||
/**
|
||||
* Call this function to clear all data flow information about
|
||||
|
||||
+10
-10
@@ -316,25 +316,25 @@ object DataFlowValueFactory {
|
||||
if (!variableDescriptor.isVar) return STABLE_VALUE
|
||||
if (variableDescriptor is SyntheticFieldDescriptor) return MUTABLE_PROPERTY
|
||||
|
||||
// Local variable classification: PREDICTABLE or UNPREDICTABLE
|
||||
// Local variable classification: STABLE or CAPTURED
|
||||
val preliminaryVisitor = PreliminaryDeclarationVisitor.getVisitorByVariable(variableDescriptor, bindingContext)
|
||||
?: return UNPREDICTABLE_VARIABLE
|
||||
// A case when we just analyse an expression alone: counts as unpredictable
|
||||
// A case when we just analyse an expression alone: counts as captured
|
||||
?: return CAPTURED_VARIABLE
|
||||
|
||||
// Analyze who writes variable
|
||||
// If there is no writer: predictable
|
||||
// If there is no writer: stable
|
||||
val writers = preliminaryVisitor.writers(variableDescriptor)
|
||||
if (writers.isEmpty()) return PREDICTABLE_VARIABLE
|
||||
if (writers.isEmpty()) return STABLE_VARIABLE
|
||||
|
||||
// If access element is inside closure: unpredictable
|
||||
// If access element is inside closure: captured
|
||||
val variableContainingDeclaration = getVariableContainingDeclaration(variableDescriptor)
|
||||
if (isAccessedInsideClosure(variableContainingDeclaration, bindingContext, accessElement)) return UNPREDICTABLE_VARIABLE
|
||||
if (isAccessedInsideClosure(variableContainingDeclaration, bindingContext, accessElement)) return CAPTURED_VARIABLE
|
||||
|
||||
// Otherwise, predictable iff considered position is BEFORE all writers except declarer itself
|
||||
// Otherwise, stable iff considered position is BEFORE all writers except declarer itself
|
||||
return if (isAccessedBeforeAllClosureWriters(variableContainingDeclaration, writers, bindingContext, accessElement))
|
||||
PREDICTABLE_VARIABLE
|
||||
STABLE_VARIABLE
|
||||
else
|
||||
UNPREDICTABLE_VARIABLE
|
||||
CAPTURED_VARIABLE
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+14
-14
@@ -75,10 +75,10 @@ internal class DelegatingDataFlowInfo private constructor(
|
||||
|
||||
override fun getCollectedNullability(key: DataFlowValue) = getNullability(key, false)
|
||||
|
||||
override fun getPredictableNullability(key: DataFlowValue) = getNullability(key, true)
|
||||
override fun getStableNullability(key: DataFlowValue) = getNullability(key, true)
|
||||
|
||||
private fun getNullability(key: DataFlowValue, predictableOnly: Boolean) =
|
||||
if (predictableOnly && !key.isPredictable) {
|
||||
private fun getNullability(key: DataFlowValue, stableOnly: Boolean) =
|
||||
if (stableOnly && !key.isStable) {
|
||||
key.immanentNullability
|
||||
}
|
||||
else {
|
||||
@@ -132,10 +132,10 @@ internal class DelegatingDataFlowInfo private constructor(
|
||||
return enrichedTypes
|
||||
}
|
||||
|
||||
override fun getPredictableTypes(key: DataFlowValue) = getPredictableTypes(key, true)
|
||||
override fun getStableTypes(key: DataFlowValue) = getStableTypes(key, true)
|
||||
|
||||
private fun getPredictableTypes(key: DataFlowValue, enrichWithNotNull: Boolean) =
|
||||
if (!key.isPredictable) LinkedHashSet() else getCollectedTypes(key, enrichWithNotNull)
|
||||
private fun getStableTypes(key: DataFlowValue, enrichWithNotNull: Boolean) =
|
||||
if (!key.isStable) LinkedHashSet() else getCollectedTypes(key, enrichWithNotNull)
|
||||
|
||||
/**
|
||||
* Call this function to clear all data flow information about
|
||||
@@ -151,11 +151,11 @@ internal class DelegatingDataFlowInfo private constructor(
|
||||
|
||||
override fun assign(a: DataFlowValue, b: DataFlowValue): DataFlowInfo {
|
||||
val nullability = Maps.newHashMap<DataFlowValue, Nullability>()
|
||||
val nullabilityOfB = getPredictableNullability(b)
|
||||
val nullabilityOfB = getStableNullability(b)
|
||||
putNullability(nullability, a, nullabilityOfB, affectReceiver = false)
|
||||
|
||||
val newTypeInfo = newTypeInfo()
|
||||
var typesForB = getPredictableTypes(b)
|
||||
var typesForB = getStableTypes(b)
|
||||
// Own type of B must be recorded separately, e.g. for a constant
|
||||
// But if its type is the same as A, there is no reason to do it
|
||||
// because own type is not saved in this set
|
||||
@@ -170,8 +170,8 @@ internal class DelegatingDataFlowInfo private constructor(
|
||||
|
||||
override fun equate(a: DataFlowValue, b: DataFlowValue, sameTypes: Boolean): DataFlowInfo {
|
||||
val builder = Maps.newHashMap<DataFlowValue, Nullability>()
|
||||
val nullabilityOfA = getPredictableNullability(a)
|
||||
val nullabilityOfB = getPredictableNullability(b)
|
||||
val nullabilityOfA = getStableNullability(a)
|
||||
val nullabilityOfB = getStableNullability(b)
|
||||
|
||||
var changed = putNullability(builder, a, nullabilityOfA.refine(nullabilityOfB)) or
|
||||
putNullability(builder, b, nullabilityOfB.refine(nullabilityOfA))
|
||||
@@ -179,8 +179,8 @@ internal class DelegatingDataFlowInfo private constructor(
|
||||
// NB: == has no guarantees of type equality, see KT-11280 for the example
|
||||
val newTypeInfo = newTypeInfo()
|
||||
if (sameTypes) {
|
||||
newTypeInfo.putAll(a, getPredictableTypes(b, false))
|
||||
newTypeInfo.putAll(b, getPredictableTypes(a, false))
|
||||
newTypeInfo.putAll(a, getStableTypes(b, false))
|
||||
newTypeInfo.putAll(b, getStableTypes(a, false))
|
||||
if (a.type != b.type) {
|
||||
// To avoid recording base types of own type
|
||||
if (!a.type.isSubtypeOf(b.type)) {
|
||||
@@ -226,8 +226,8 @@ internal class DelegatingDataFlowInfo private constructor(
|
||||
|
||||
override fun disequate(a: DataFlowValue, b: DataFlowValue): DataFlowInfo {
|
||||
val builder = Maps.newHashMap<DataFlowValue, Nullability>()
|
||||
val nullabilityOfA = getPredictableNullability(a)
|
||||
val nullabilityOfB = getPredictableNullability(b)
|
||||
val nullabilityOfA = getStableNullability(a)
|
||||
val nullabilityOfB = getStableNullability(b)
|
||||
|
||||
val changed = putNullability(builder, a, nullabilityOfA.refine(nullabilityOfB.invert())) or
|
||||
putNullability(builder, b, nullabilityOfB.refine(nullabilityOfA.invert()))
|
||||
|
||||
+4
-4
@@ -116,7 +116,7 @@ class SmartCastManager {
|
||||
recordExpressionType: Boolean
|
||||
) {
|
||||
if (KotlinBuiltIns.isNullableNothing(type)) return
|
||||
if (dataFlowValue.isPredictable) {
|
||||
if (dataFlowValue.isStable) {
|
||||
trace.record(SMARTCAST, expression, type)
|
||||
if (recordExpressionType) {
|
||||
//TODO
|
||||
@@ -154,10 +154,10 @@ class SmartCastManager {
|
||||
if (expression != null) {
|
||||
recordCastOrError(expression, possibleType, c.trace, dataFlowValue, recordExpressionType)
|
||||
}
|
||||
else if (calleeExpression != null && dataFlowValue.isPredictable) {
|
||||
else if (calleeExpression != null && dataFlowValue.isStable) {
|
||||
c.trace.record(IMPLICIT_RECEIVER_SMARTCAST, calleeExpression, possibleType)
|
||||
}
|
||||
return SmartCastResult(possibleType, dataFlowValue.isPredictable)
|
||||
return SmartCastResult(possibleType, dataFlowValue.isStable)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ class SmartCastManager {
|
||||
recordCastOrError(expression, dataFlowValue.type, c.trace, dataFlowValue, recordExpressionType)
|
||||
}
|
||||
|
||||
return SmartCastResult(dataFlowValue.type, immanentlyNotNull || dataFlowValue.isPredictable)
|
||||
return SmartCastResult(dataFlowValue.type, immanentlyNotNull || dataFlowValue.isStable)
|
||||
}
|
||||
return checkAndRecordPossibleCast(dataFlowValue, nullableExpectedType, expression, c, calleeExpression, recordExpressionType)
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ private class DataFlowDecoratorImpl(private val resolutionContext: ResolutionCon
|
||||
|
||||
override fun getDataFlowValue(receiver: ReceiverValue): DataFlowValue = getSmartCastInfo(receiver).dataFlowValue
|
||||
|
||||
override fun isStableReceiver(receiver: ReceiverValue): Boolean = getSmartCastInfo(receiver).dataFlowValue.isPredictable
|
||||
override fun isStableReceiver(receiver: ReceiverValue): Boolean = getSmartCastInfo(receiver).dataFlowValue.isStable
|
||||
|
||||
override fun getSmartCastTypes(receiver: ReceiverValue): Set<KotlinType> = getSmartCastInfo(receiver).possibleTypes
|
||||
|
||||
|
||||
+4
-4
@@ -142,7 +142,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
// Receivers are normally analyzed at resolve, with an exception of KT-10175
|
||||
if (type != null && !type.isError() && !isLValueOrUnsafeReceiver(expression)) {
|
||||
DataFlowValue dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, type, context);
|
||||
Nullability nullability = context.dataFlowInfo.getPredictableNullability(dataFlowValue);
|
||||
Nullability nullability = context.dataFlowInfo.getStableNullability(dataFlowValue);
|
||||
if (!nullability.canBeNonNull() && nullability.canBeNull()) {
|
||||
if (isDangerousWithNull(expression, context)) {
|
||||
context.trace.report(ALWAYS_NULL.on(expression));
|
||||
@@ -878,7 +878,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
|
||||
private static boolean isKnownToBeNotNull(KtExpression expression, KotlinType jetType, ExpressionTypingContext context) {
|
||||
DataFlowValue dataFlowValue = createDataFlowValue(expression, jetType, context);
|
||||
return !context.dataFlowInfo.getPredictableNullability(dataFlowValue).canBeNull();
|
||||
return !context.dataFlowInfo.getStableNullability(dataFlowValue).canBeNull();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1221,7 +1221,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
boolean jumpInRight = KotlinBuiltIns.isNothing(rightType);
|
||||
DataFlowValue nullValue = DataFlowValue.nullValue(components.builtIns);
|
||||
// left argument is considered not-null if it's not-null also in right part or if we have jump in right part
|
||||
if (jumpInRight || !rightDataFlowInfo.getPredictableNullability(leftValue).canBeNull()) {
|
||||
if (jumpInRight || !rightDataFlowInfo.getStableNullability(leftValue).canBeNull()) {
|
||||
dataFlowInfo = dataFlowInfo.disequate(leftValue, nullValue);
|
||||
if (left instanceof KtBinaryExpressionWithTypeRHS) {
|
||||
dataFlowInfo = establishSubtypingForTypeRHS((KtBinaryExpressionWithTypeRHS) left, dataFlowInfo, context);
|
||||
@@ -1360,7 +1360,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
new Function1<DataFlowValue, Nullability>() {
|
||||
@Override
|
||||
public Nullability invoke(DataFlowValue value) {
|
||||
return context.dataFlowInfo.getPredictableNullability(value);
|
||||
return context.dataFlowInfo.getStableNullability(value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -341,7 +341,7 @@ public class DataFlowAnalyzer {
|
||||
) {
|
||||
DataFlowValue dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, type, c);
|
||||
Collection<KotlinType> possibleTypes = Sets.newHashSet(type);
|
||||
possibleTypes.addAll(dataFlowInfo.getPredictableTypes(dataFlowValue));
|
||||
possibleTypes.addAll(dataFlowInfo.getStableTypes(dataFlowValue));
|
||||
return possibleTypes;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -34,9 +34,9 @@ class PreliminaryLoopVisitor private constructor() : AssignedVariablesSearcher()
|
||||
val nullabilityMap = resultFlowInfo.completeNullabilityInfo
|
||||
val valueSetToClear = LinkedHashSet<DataFlowValue>()
|
||||
for (value in nullabilityMap.keys) {
|
||||
// Only predictable variables are under interest here
|
||||
// Only stable variables are under interest here
|
||||
val identifierInfo = value.identifierInfo
|
||||
if (value.kind == DataFlowValue.Kind.PREDICTABLE_VARIABLE && identifierInfo is IdentifierInfo.Variable) {
|
||||
if (value.kind == DataFlowValue.Kind.STABLE_VARIABLE && identifierInfo is IdentifierInfo.Variable) {
|
||||
val variableDescriptor = identifierInfo.variable
|
||||
if (variableDescriptor is LocalVariableDescriptor && hasWriters(variableDescriptor)) {
|
||||
valueSetToClear.add(value)
|
||||
|
||||
Reference in New Issue
Block a user