Data flow values refactoring: removed DataFlowValue.kind.isStable, renamed DataFlowValue.isPredictable -> DataFlowValue.isStable

This commit is contained in:
Mikhail Glukhikh
2016-07-27 16:16:38 +03:00
parent 915e36cb02
commit 6e391854a0
22 changed files with 70 additions and 75 deletions
@@ -81,7 +81,7 @@ object RuntimeAssertionsTypeChecker : AdditionalTypeChecker {
expressionType,
object : RuntimeAssertionInfo.DataFlowExtras {
override val canBeNull: Boolean
get() = c.dataFlowInfo.getPredictableNullability(dataFlowValue).canBeNull()
get() = c.dataFlowInfo.getStableNullability(dataFlowValue).canBeNull()
override val possibleTypes: Set<KotlinType>
get() = c.dataFlowInfo.getCollectedTypes(dataFlowValue)
override val presentableText: String
@@ -46,7 +46,7 @@ object ProtectedSyntheticExtensionCallChecker : CallChecker {
if (resolvedCall.dispatchReceiver != null && resolvedCall.extensionReceiver !is ReceiverValue) return
val receiverValue = resolvedCall.extensionReceiver as ReceiverValue
val receiverTypes = listOf(receiverValue.type) + context.dataFlowInfo.getPredictableTypes(
val receiverTypes = listOf(receiverValue.type) + context.dataFlowInfo.getStableTypes(
DataFlowValueFactory.createDataFlowValue(receiverValue, context.trace.bindingContext, context.scope.ownerDescriptor)
)
@@ -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)) {
@@ -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
@@ -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
}
/**
@@ -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()))
@@ -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
@@ -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;
}
@@ -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)
@@ -38,7 +38,7 @@ class DataFlowValue(val identifierInfo: IdentifierInfo,
// Local value, or parameter, or private / internal member value without open / custom getter,
// or protected / public member value from the same module without open / custom getter
// Smart casts are completely safe
STABLE_VALUE("stable"),
STABLE_VALUE("stable val"),
// Member value with open / custom getter
// Smart casts are not safe
PROPERTY_WITH_GETTER("custom getter", "property that has open or custom getter"),
@@ -47,10 +47,10 @@ class DataFlowValue(val identifierInfo: IdentifierInfo,
ALIEN_PUBLIC_PROPERTY("alien public", "public API property declared in different module"),
// Local variable not yet captured by a changing closure
// Smart casts are safe but possible changes in loops / closures ahead must be taken into account
PREDICTABLE_VARIABLE("predictable", "local variable that can be changed since the check in a loop"),
STABLE_VARIABLE("stable var", "local variable that can be changed since the check in a loop"),
// Local variable already captured by a changing closure
// Smart casts are not safe
UNPREDICTABLE_VARIABLE("unpredictable", "local variable that is captured by a changing closure"),
CAPTURED_VARIABLE("captured var", "local variable that is captured by a changing closure"),
// Member variable regardless of its visibility
// Smart casts are not safe
MUTABLE_PROPERTY("member", "mutable property that could have been changed by this time"),
@@ -59,17 +59,13 @@ class DataFlowValue(val identifierInfo: IdentifierInfo,
OTHER("other", "complex expression");
override fun toString() = str
fun isStable() = this == STABLE_VALUE
}
/**
* Both stable values and predictable local variables are considered "predictable".
* Predictable means here we do not expect some sudden change of their values,
* Stable means here we do not expect some sudden change of their values,
* like accessing mutable properties in another thread, so smart casts can be used safely.
*/
val isPredictable = (kind == Kind.STABLE_VALUE || kind == Kind.PREDICTABLE_VARIABLE)
@JvmName("isPredictable") get
val isStable = (kind == Kind.STABLE_VALUE || kind == Kind.STABLE_VARIABLE)
override fun equals(other: Any?): Boolean {
if (this === other) return true
@@ -72,7 +72,7 @@ interface IdentifierInfo {
val safe: Boolean,
val receiverType: KotlinType?
) : IdentifierInfo {
override val kind: DataFlowValue.Kind get() = if (receiverInfo.kind.isStable()) selectorInfo.kind else OTHER
override val kind: DataFlowValue.Kind get() = if (receiverInfo.kind == STABLE_VALUE) selectorInfo.kind else OTHER
override fun equals(other: Any?) = other is Qualified && receiverInfo == other.receiverInfo && selectorInfo == other.selectorInfo
@@ -186,7 +186,7 @@ class ReferenceVariantsHelper(
listOf(useReceiverType)
}
else {
callTypeAndReceiver.receiverTypes(bindingContext, contextElement, moduleDescriptor, resolutionFacade, predictableSmartCastsOnly = false)!!
callTypeAndReceiver.receiverTypes(bindingContext, contextElement, moduleDescriptor, resolutionFacade, stableSmartCastsOnly = false)!!
}
descriptors.processAll(implicitReceiverTypes, explicitReceiverTypes, resolutionScope, callType, kindFilter, nameFilter)
@@ -244,7 +244,7 @@ class ReferenceVariantsHelper(
listOf(useReceiverType)
}
else {
callTypeAndReceiver.receiverTypes(bindingContext, contextElement, moduleDescriptor, resolutionFacade, predictableSmartCastsOnly = false)!!
callTypeAndReceiver.receiverTypes(bindingContext, contextElement, moduleDescriptor, resolutionFacade, stableSmartCastsOnly = false)!!
}
val constructorFilter = { descriptor: ClassDescriptor -> if (isStatic) true else descriptor.isInner }
@@ -213,7 +213,7 @@ fun CallTypeAndReceiver<*, *>.receiverTypes(
contextElement: PsiElement,
moduleDescriptor: ModuleDescriptor,
resolutionFacade: ResolutionFacade,
predictableSmartCastsOnly: Boolean
stableSmartCastsOnly: Boolean
): Collection<KotlinType>? {
val receiverExpression: KtExpression?
when (this) {
@@ -225,7 +225,7 @@ fun CallTypeAndReceiver<*, *>.receiverTypes(
is DoubleColonLHS.Expression -> {
val receiverValue = ExpressionReceiver.create(receiver, lhs.type, bindingContext)
return receiverValueTypes(receiverValue, lhs.dataFlowInfo, bindingContext, moduleDescriptor, predictableSmartCastsOnly)
return receiverValueTypes(receiverValue, lhs.dataFlowInfo, bindingContext, moduleDescriptor, stableSmartCastsOnly)
}
}
}
@@ -281,7 +281,7 @@ fun CallTypeAndReceiver<*, *>.receiverTypes(
val dataFlowInfo = bindingContext.getDataFlowInfo(contextElement)
return receiverValues.flatMap {
receiverValueTypes(it, dataFlowInfo, bindingContext, moduleDescriptor, predictableSmartCastsOnly)
receiverValueTypes(it, dataFlowInfo, bindingContext, moduleDescriptor, stableSmartCastsOnly)
}
}
@@ -290,10 +290,10 @@ private fun receiverValueTypes(
dataFlowInfo: DataFlowInfo,
bindingContext: BindingContext,
moduleDescriptor: ModuleDescriptor,
predictableSmartCastsOnly: Boolean
stableSmartCastsOnly: Boolean
): List<KotlinType> {
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiverValue, bindingContext, moduleDescriptor)
return if (dataFlowValue.isPredictable || !predictableSmartCastsOnly) { // we don't include smart cast receiver types for "unpredictable" receiver value to mark members grayed
return if (dataFlowValue.isStable || !stableSmartCastsOnly) { // we don't include smart cast receiver types for "unstable" receiver value to mark members grayed
SmartCastManager().getSmartCastVariantsWithLessSpecificExcluded(receiverValue, bindingContext, moduleDescriptor, dataFlowInfo)
}
else {
@@ -439,7 +439,7 @@ abstract class CompletionSession(
var receiverTypes = callTypeAndReceiver.receiverTypes(
bindingContext, nameExpression, moduleDescriptor, resolutionFacade,
predictableSmartCastsOnly = true /* we don't include smart cast receiver types for "unpredictable" receiver value to mark members grayed */)
stableSmartCastsOnly = true /* we don't include smart cast receiver types for "unstable" receiver value to mark members grayed */)
if (callTypeAndReceiver is CallTypeAndReceiver.SAFE || isDebuggerContext) {
receiverTypes = receiverTypes?.map { it.makeNotNullable() }
@@ -132,7 +132,7 @@ class KotlinIndicesHelper(
bindingContext: BindingContext,
nameFilter: (String) -> Boolean
): Collection<CallableDescriptor> {
val receiverTypes = callTypeAndReceiver.receiverTypes(bindingContext, position, moduleDescriptor, resolutionFacade, predictableSmartCastsOnly = false)
val receiverTypes = callTypeAndReceiver.receiverTypes(bindingContext, position, moduleDescriptor, resolutionFacade, stableSmartCastsOnly = false)
?: return emptyList()
return getCallableTopLevelExtensions(callTypeAndReceiver, receiverTypes, nameFilter)
}
@@ -67,7 +67,7 @@ class SurroundWithNullCheckFix(
else -> return null
} as? KtReferenceExpression ?: return null
if (!nullableExpression.isPredictable()) return null
if (!nullableExpression.isStable()) return null
return SurroundWithNullCheckFix(expression, nullableExpression)
}
@@ -80,7 +80,7 @@ class SurroundWithNullCheckFix(
val forExpression = nullableExpression.parent?.parent as? KtForExpression ?: return null
if (forExpression.parent !is KtBlockExpression) return null
if (!nullableExpression.isPredictable()) return null
if (!nullableExpression.isStable()) return null
return SurroundWithNullCheckFix(forExpression, nullableExpression)
}
@@ -97,16 +97,16 @@ class SurroundWithNullCheckFix(
if (!isNullabilityMismatch(expected = typeMismatch.a, actual = typeMismatch.b)) return null
if (!nullableExpression.isPredictable()) return null
if (!nullableExpression.isStable()) return null
return SurroundWithNullCheckFix(call, nullableExpression)
}
}
}
private fun KtExpression.isPredictable(): Boolean {
private fun KtExpression.isStable(): Boolean {
val context = this.analyze()
val nullableType = this.getType(context) ?: return false
val containingDescriptor = this.getResolutionScope(context, this.getResolutionFacade()).ownerDescriptor
return DataFlowValueFactory.createDataFlowValue(this, nullableType, context, containingDescriptor).isPredictable
return DataFlowValueFactory.createDataFlowValue(this, nullableType, context, containingDescriptor).isStable
}
@@ -47,7 +47,7 @@ abstract class AbstractDataFlowValueRenderingTest: KotlinLightCodeInsightFixture
private fun DataFlowValue.render() =
// If it is not a stable identifier, there's no point in rendering it
if (!isPredictable) null
if (!isStable) null
else identifierInfo.render()
override fun getTestDataPath() : String {