Refactor DataFlowValueFactory into proper component

This commit is contained in:
Dmitry Savvinov
2018-02-13 13:48:08 +03:00
parent 03567a1c01
commit 0929673576
62 changed files with 397 additions and 242 deletions
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactoryImpl
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
@@ -56,7 +57,8 @@ fun legacyCalcTypeForIeee754ArithmeticIfNeeded(
) )
} }
val dataFlow = DataFlowValueFactory.createDataFlowValue( // NB. Using DataFlowValueFactoryImpl is a hack, but it is ok for 'legacy'
val dataFlow = DataFlowValueFactoryImpl().createDataFlowValue(
expression!!, expression!!,
ktType, ktType,
bindingContext, bindingContext,
@@ -30,7 +30,6 @@ import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
@@ -92,7 +91,7 @@ class RuntimeAssertionsDataFlowExtras(
private val expression: KtExpression private val expression: KtExpression
) : RuntimeAssertionInfo.DataFlowExtras { ) : RuntimeAssertionInfo.DataFlowExtras {
private val dataFlowValue by lazy(LazyThreadSafetyMode.PUBLICATION) { private val dataFlowValue by lazy(LazyThreadSafetyMode.PUBLICATION) {
DataFlowValueFactory.createDataFlowValue(expression, expressionType, c) c.dataFlowValueFactory.createDataFlowValue(expression, expressionType, c)
} }
override val canBeNull: Boolean override val canBeNull: Boolean
@@ -30,7 +30,6 @@ import org.jetbrains.kotlin.resolve.calls.context.CallResolutionContext
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.smartcasts.Nullability import org.jetbrains.kotlin.resolve.calls.smartcasts.Nullability
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
@@ -44,7 +43,7 @@ class JavaNullabilityChecker : AdditionalTypeChecker {
doCheckType( doCheckType(
expressionType, expressionType,
c.expectedType, c.expectedType,
{ DataFlowValueFactory.createDataFlowValue(expression, expressionType, c) } , { c.dataFlowValueFactory.createDataFlowValue(expression, expressionType, c) } ,
c.dataFlowInfo c.dataFlowInfo
) { expectedMustNotBeNull, actualMayBeNull -> ) { expectedMustNotBeNull, actualMayBeNull ->
c.trace.report(ErrorsJvm.NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS.on(expression, expectedMustNotBeNull, actualMayBeNull)) c.trace.report(ErrorsJvm.NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS.on(expression, expectedMustNotBeNull, actualMayBeNull))
@@ -61,7 +60,7 @@ class JavaNullabilityChecker : AdditionalTypeChecker {
val context = c.trace.bindingContext val context = c.trace.bindingContext
if (WhenChecker.getEnumMissingCases(expression, context, enumClassDescriptor).isEmpty() if (WhenChecker.getEnumMissingCases(expression, context, enumClassDescriptor).isEmpty()
&& !WhenChecker.containsNullCase(expression, context)) { && !WhenChecker.containsNullCase(expression, context)) {
val subjectDataFlowValue = DataFlowValueFactory.createDataFlowValue(subjectExpression, type, c) val subjectDataFlowValue = c.dataFlowValueFactory.createDataFlowValue(subjectExpression, type, c)
val dataFlowInfo = c.trace[BindingContext.EXPRESSION_TYPE_INFO, subjectExpression]?.dataFlowInfo val dataFlowInfo = c.trace[BindingContext.EXPRESSION_TYPE_INFO, subjectExpression]?.dataFlowInfo
if (dataFlowInfo != null && !dataFlowInfo.getStableNullability(subjectDataFlowValue).canBeNull()) { if (dataFlowInfo != null && !dataFlowInfo.getStableNullability(subjectDataFlowValue).canBeNull()) {
return return
@@ -77,7 +76,7 @@ class JavaNullabilityChecker : AdditionalTypeChecker {
val baseExpressionType = c.trace.getType(baseExpression) ?: return val baseExpressionType = c.trace.getType(baseExpression) ?: return
doIfNotNull( doIfNotNull(
baseExpressionType, baseExpressionType,
{ DataFlowValueFactory.createDataFlowValue(baseExpression, baseExpressionType, c) }, { c.dataFlowValueFactory.createDataFlowValue(baseExpression, baseExpressionType, c) },
c c
) { ) {
c.trace.report(Errors.UNNECESSARY_NOT_NULL_ASSERTION.on(expression.operationReference, baseExpressionType)) c.trace.report(Errors.UNNECESSARY_NOT_NULL_ASSERTION.on(expression.operationReference, baseExpressionType))
@@ -105,7 +104,7 @@ class JavaNullabilityChecker : AdditionalTypeChecker {
override fun checkReceiver(receiverParameter: ReceiverParameterDescriptor, receiverArgument: ReceiverValue, safeAccess: Boolean, c: CallResolutionContext<*>) { override fun checkReceiver(receiverParameter: ReceiverParameterDescriptor, receiverArgument: ReceiverValue, safeAccess: Boolean, c: CallResolutionContext<*>) {
val dataFlowValue by lazy(LazyThreadSafetyMode.NONE) { val dataFlowValue by lazy(LazyThreadSafetyMode.NONE) {
DataFlowValueFactory.createDataFlowValue(receiverArgument, c) c.dataFlowValueFactory.createDataFlowValue(receiverArgument, c)
} }
if (safeAccess) { if (safeAccess) {
@@ -59,7 +59,7 @@ object JvmArrayVariableInLoopAssignmentChecker : AdditionalTypeChecker {
if (!isOuterForLoopRangeVariable(expression, variableDescriptor, c)) return if (!isOuterForLoopRangeVariable(expression, variableDescriptor, c)) return
val dataFlowValueKind = DataFlowValueFactory.createDataFlowValue(lhsExpression, variableType, c).kind val dataFlowValueKind = c.dataFlowValueFactory.createDataFlowValue(lhsExpression, variableType, c).kind
if (dataFlowValueKind != DataFlowValue.Kind.STABLE_VARIABLE) return if (dataFlowValueKind != DataFlowValue.Kind.STABLE_VARIABLE) return
c.trace.report(ErrorsJvm.ASSIGNMENT_TO_ARRAY_LOOP_VARIABLE.on(lhsExpression)) c.trace.report(ErrorsJvm.ASSIGNMENT_TO_ARRAY_LOOP_VARIABLE.on(lhsExpression))
@@ -49,7 +49,7 @@ object ProtectedSyntheticExtensionCallChecker : CallChecker {
val receiverValue = resolvedCall.extensionReceiver as ReceiverValue val receiverValue = resolvedCall.extensionReceiver as ReceiverValue
val receiverTypes = listOf(receiverValue.type) + context.dataFlowInfo.getStableTypes( val receiverTypes = listOf(receiverValue.type) + context.dataFlowInfo.getStableTypes(
DataFlowValueFactory.createDataFlowValue(receiverValue, context.trace.bindingContext, context.scope.ownerDescriptor), context.dataFlowValueFactory.createDataFlowValue(receiverValue, context.trace.bindingContext, context.scope.ownerDescriptor),
context.languageVersionSettings context.languageVersionSettings
) )
@@ -37,8 +37,9 @@ import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.smartcasts.ConditionalDataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.ConditionalDataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
class EffectSystem(val languageVersionSettings: LanguageVersionSettings) { class EffectSystem(val languageVersionSettings: LanguageVersionSettings, val dataFlowValueFactory: DataFlowValueFactory) {
fun getDataFlowInfoForFinishedCall( fun getDataFlowInfoForFinishedCall(
resolvedCall: ResolvedCall<*>, resolvedCall: ResolvedCall<*>,
@@ -120,7 +121,7 @@ class EffectSystem(val languageVersionSettings: LanguageVersionSettings) {
} }
private fun getNonTrivialComputation(expression: KtExpression, trace: BindingTrace, moduleDescriptor: ModuleDescriptor): Computation? { private fun getNonTrivialComputation(expression: KtExpression, trace: BindingTrace, moduleDescriptor: ModuleDescriptor): Computation? {
val computation = EffectsExtractingVisitor(trace, moduleDescriptor).extractOrGetCached(expression) val computation = EffectsExtractingVisitor(trace, moduleDescriptor, dataFlowValueFactory).extractOrGetCached(expression)
return if (computation == UNKNOWN_COMPUTATION) null else computation return if (computation == UNKNOWN_COMPUTATION) null else computation
} }
} }
@@ -51,7 +51,8 @@ import org.jetbrains.kotlin.utils.addIfNotNull
*/ */
class EffectsExtractingVisitor( class EffectsExtractingVisitor(
private val trace: BindingTrace, private val trace: BindingTrace,
private val moduleDescriptor: ModuleDescriptor private val moduleDescriptor: ModuleDescriptor,
private val dataFlowValueFactory: DataFlowValueFactory
) : KtVisitor<Computation, Unit>() { ) : KtVisitor<Computation, Unit>() {
fun extractOrGetCached(element: KtElement): Computation { fun extractOrGetCached(element: KtElement): Computation {
trace[BindingContext.EXPRESSION_EFFECTS, element]?.let { return it } trace[BindingContext.EXPRESSION_EFFECTS, element]?.let { return it }
@@ -143,7 +144,7 @@ class EffectsExtractingVisitor(
} }
private fun KtExpression.createDataFlowValue(): DataFlowValue? { private fun KtExpression.createDataFlowValue(): DataFlowValue? {
return DataFlowValueFactory.createDataFlowValue( return dataFlowValueFactory.createDataFlowValue(
expression = this, expression = this,
type = trace.getType(this) ?: return null, type = trace.getType(this) ?: return null,
bindingContext = trace.bindingContext, bindingContext = trace.bindingContext,
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
import org.jetbrains.kotlin.incremental.components.LookupTracker import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.* import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactoryImpl
import org.jetbrains.kotlin.resolve.calls.tower.KotlinResolutionStatelessCallbacksImpl import org.jetbrains.kotlin.resolve.calls.tower.KotlinResolutionStatelessCallbacksImpl
import org.jetbrains.kotlin.resolve.checkers.ExperimentalUsageChecker import org.jetbrains.kotlin.resolve.checkers.ExperimentalUsageChecker
import org.jetbrains.kotlin.resolve.lazy.* import org.jetbrains.kotlin.resolve.lazy.*
@@ -64,6 +65,7 @@ fun StorageComponentContainer.configureModule(
private fun StorageComponentContainer.configurePlatformIndependentComponents() { private fun StorageComponentContainer.configurePlatformIndependentComponents() {
useImpl<SupertypeLoopCheckerImpl>() useImpl<SupertypeLoopCheckerImpl>()
useImpl<KotlinResolutionStatelessCallbacksImpl>() useImpl<KotlinResolutionStatelessCallbacksImpl>()
useImpl<DataFlowValueFactoryImpl>()
useImpl<ExperimentalUsageChecker>() useImpl<ExperimentalUsageChecker>()
useImpl<ExperimentalUsageChecker.Overrides>() useImpl<ExperimentalUsageChecker.Overrides>()
@@ -42,6 +42,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.toHandle
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor
import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.resolve.scopes.ScopeUtils import org.jetbrains.kotlin.resolve.scopes.ScopeUtils
@@ -63,7 +64,8 @@ class DelegatedPropertyResolver(
private val builtIns: KotlinBuiltIns, private val builtIns: KotlinBuiltIns,
private val fakeCallResolver: FakeCallResolver, private val fakeCallResolver: FakeCallResolver,
private val expressionTypingServices: ExpressionTypingServices, private val expressionTypingServices: ExpressionTypingServices,
private val languageVersionSettings: LanguageVersionSettings private val languageVersionSettings: LanguageVersionSettings,
private val dataFlowValueFactory: DataFlowValueFactory
) { ) {
fun resolvePropertyDelegate( fun resolvePropertyDelegate(
@@ -314,7 +316,7 @@ class DelegatedPropertyResolver(
else else
TypeUtils.NO_EXPECTED_TYPE TypeUtils.NO_EXPECTED_TYPE
val context = ExpressionTypingContext.newContext(trace, delegateFunctionsScope, dataFlowInfo, expectedType, languageVersionSettings) val context = ExpressionTypingContext.newContext(trace, delegateFunctionsScope, dataFlowInfo, expectedType, languageVersionSettings, dataFlowValueFactory)
val hasThis = propertyDescriptor.extensionReceiverParameter != null || propertyDescriptor.dispatchReceiverParameter != null val hasThis = propertyDescriptor.extensionReceiverParameter != null || propertyDescriptor.dispatchReceiverParameter != null
@@ -352,7 +354,7 @@ class DelegatedPropertyResolver(
initializerScope: LexicalScope, initializerScope: LexicalScope,
dataFlowInfo: DataFlowInfo dataFlowInfo: DataFlowInfo
): OverloadResolutionResults<FunctionDescriptor> { ): OverloadResolutionResults<FunctionDescriptor> {
val context = ExpressionTypingContext.newContext(trace, initializerScope, dataFlowInfo, NO_EXPECTED_TYPE, languageVersionSettings) val context = ExpressionTypingContext.newContext(trace, initializerScope, dataFlowInfo, NO_EXPECTED_TYPE, languageVersionSettings, dataFlowValueFactory)
return getProvideDelegateMethod(propertyDescriptor, delegateExpression, delegateExpressionType, context) return getProvideDelegateMethod(propertyDescriptor, delegateExpression, delegateExpressionType, context)
} }
@@ -573,7 +575,7 @@ class DelegatedPropertyResolver(
val contextForProvideDelegate = ExpressionTypingContext.newContext( val contextForProvideDelegate = ExpressionTypingContext.newContext(
traceToResolveConventionMethods, scopeForDelegate, delegateTypeInfo.dataFlowInfo, traceToResolveConventionMethods, scopeForDelegate, delegateTypeInfo.dataFlowInfo,
NO_EXPECTED_TYPE, ContextDependency.DEPENDENT, StatementFilter.NONE, NO_EXPECTED_TYPE, ContextDependency.DEPENDENT, StatementFilter.NONE,
languageVersionSettings languageVersionSettings, dataFlowValueFactory
) )
val delegateTypeConstructor = delegateTypeInfo.type?.constructor val delegateTypeConstructor = delegateTypeInfo.type?.constructor
@@ -46,6 +46,7 @@ import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt; import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfoFactory; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfoFactory;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory;
import org.jetbrains.kotlin.resolve.calls.util.UnderscoreUtilKt; import org.jetbrains.kotlin.resolve.calls.util.UnderscoreUtilKt;
import org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension; import org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension;
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil; import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil;
@@ -88,6 +89,7 @@ public class DescriptorResolver {
private final SyntheticResolveExtension syntheticResolveExtension; private final SyntheticResolveExtension syntheticResolveExtension;
private final TypeApproximator typeApproximator; private final TypeApproximator typeApproximator;
private final DeclarationReturnTypeSanitizer declarationReturnTypeSanitizer; private final DeclarationReturnTypeSanitizer declarationReturnTypeSanitizer;
private final DataFlowValueFactory dataFlowValueFactory;
public DescriptorResolver( public DescriptorResolver(
@NotNull AnnotationResolver annotationResolver, @NotNull AnnotationResolver annotationResolver,
@@ -105,7 +107,8 @@ public class DescriptorResolver {
@NotNull WrappedTypeFactory wrappedTypeFactory, @NotNull WrappedTypeFactory wrappedTypeFactory,
@NotNull Project project, @NotNull Project project,
@NotNull TypeApproximator approximator, @NotNull TypeApproximator approximator,
@NotNull DeclarationReturnTypeSanitizer declarationReturnTypeSanitizer @NotNull DeclarationReturnTypeSanitizer declarationReturnTypeSanitizer,
@NotNull DataFlowValueFactory dataFlowValueFactory
) { ) {
this.annotationResolver = annotationResolver; this.annotationResolver = annotationResolver;
this.builtIns = builtIns; this.builtIns = builtIns;
@@ -123,6 +126,7 @@ public class DescriptorResolver {
this.syntheticResolveExtension = SyntheticResolveExtension.Companion.getInstance(project); this.syntheticResolveExtension = SyntheticResolveExtension.Companion.getInstance(project);
typeApproximator = approximator; typeApproximator = approximator;
this.declarationReturnTypeSanitizer = declarationReturnTypeSanitizer; this.declarationReturnTypeSanitizer = declarationReturnTypeSanitizer;
this.dataFlowValueFactory = dataFlowValueFactory;
} }
public List<KotlinType> resolveSupertypes( public List<KotlinType> resolveSupertypes(
@@ -340,7 +344,8 @@ public class DescriptorResolver {
scope, scope,
destructuringDeclaration, new TransientReceiver(type), /* initializer = */ null, destructuringDeclaration, new TransientReceiver(type), /* initializer = */ null,
ExpressionTypingContext.newContext( ExpressionTypingContext.newContext(
trace, scopeForDestructuring, DataFlowInfoFactory.EMPTY, TypeUtils.NO_EXPECTED_TYPE, languageVersionSettings trace, scopeForDestructuring, DataFlowInfoFactory.EMPTY, TypeUtils.NO_EXPECTED_TYPE,
languageVersionSettings, dataFlowValueFactory
) )
); );
@@ -785,7 +790,7 @@ public class DescriptorResolver {
KtExpression initializer = destructuringDeclaration.getInitializer(); KtExpression initializer = destructuringDeclaration.getInitializer();
ExpressionTypingContext context = ExpressionTypingContext.newContext( ExpressionTypingContext context = ExpressionTypingContext.newContext(
trace, scopeForDeclarationResolution, dataFlowInfo, TypeUtils.NO_EXPECTED_TYPE, languageVersionSettings trace, scopeForDeclarationResolution, dataFlowInfo, TypeUtils.NO_EXPECTED_TYPE, languageVersionSettings, dataFlowValueFactory
); );
ExpressionReceiver receiver = createReceiverForDestructuringDeclaration(destructuringDeclaration, context); ExpressionReceiver receiver = createReceiverForDestructuringDeclaration(destructuringDeclaration, context);
@@ -48,7 +48,8 @@ class LocalVariableResolver(
private val annotationResolver: AnnotationResolver, private val annotationResolver: AnnotationResolver,
private val variableTypeAndInitializerResolver: VariableTypeAndInitializerResolver, private val variableTypeAndInitializerResolver: VariableTypeAndInitializerResolver,
private val delegatedPropertyResolver: DelegatedPropertyResolver, private val delegatedPropertyResolver: DelegatedPropertyResolver,
private val languageVersionSettings: LanguageVersionSettings private val languageVersionSettings: LanguageVersionSettings,
private val dataFlowValueFactory: DataFlowValueFactory
) { ) {
fun process( fun process(
@@ -108,7 +109,7 @@ class LocalVariableResolver(
val dataFlowInfo = typeInfo.dataFlowInfo val dataFlowInfo = typeInfo.dataFlowInfo
val type = typeInfo.type val type = typeInfo.type
if (type != null) { if (type != null) {
val initializerDataFlowValue = DataFlowValueFactory.createDataFlowValue(initializer, type, context) val initializerDataFlowValue = dataFlowValueFactory.createDataFlowValue(initializer, type, context)
if (!propertyDescriptor.isVar && initializerDataFlowValue.canBeBound) { if (!propertyDescriptor.isVar && initializerDataFlowValue.canBeBound) {
context.trace.record(BindingContext.BOUND_INITIALIZER_VALUE, propertyDescriptor, initializerDataFlowValue) context.trace.record(BindingContext.BOUND_INITIALIZER_VALUE, propertyDescriptor, initializerDataFlowValue)
} }
@@ -116,7 +117,7 @@ class LocalVariableResolver(
// We can comment this condition to take them into account, like here: var s: String? = "xyz" // We can comment this condition to take them into account, like here: var s: String? = "xyz"
// In this case s will be not-nullable until it is changed // In this case s will be not-nullable until it is changed
if (property.typeReference == null) { if (property.typeReference == null) {
val variableDataFlowValue = DataFlowValueFactory.createDataFlowValueForProperty( val variableDataFlowValue = dataFlowValueFactory.createDataFlowValueForProperty(
property, propertyDescriptor, context.trace.bindingContext, property, propertyDescriptor, context.trace.bindingContext,
DescriptorUtils.getContainingModuleOrNull(scope.ownerDescriptor) DescriptorUtils.getContainingModuleOrNull(scope.ownerDescriptor)
) )
@@ -46,6 +46,7 @@ import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.makeNullableTypeIfSaf
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy
import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
@@ -61,7 +62,8 @@ class CallCompleter(
private val callCheckers: Iterable<CallChecker>, private val callCheckers: Iterable<CallChecker>,
private val moduleDescriptor: ModuleDescriptor, private val moduleDescriptor: ModuleDescriptor,
private val deprecationResolver: DeprecationResolver, private val deprecationResolver: DeprecationResolver,
private val effectSystem: EffectSystem private val effectSystem: EffectSystem,
private val dataFlowValueFactory: DataFlowValueFactory
) { ) {
fun <D : CallableDescriptor> completeCall( fun <D : CallableDescriptor> completeCall(
context: BasicCallResolutionContext, context: BasicCallResolutionContext,
@@ -73,7 +73,8 @@ class CallExpressionResolver(
private val dataFlowAnalyzer: DataFlowAnalyzer, private val dataFlowAnalyzer: DataFlowAnalyzer,
private val builtIns: KotlinBuiltIns, private val builtIns: KotlinBuiltIns,
private val qualifiedExpressionResolver: QualifiedExpressionResolver, private val qualifiedExpressionResolver: QualifiedExpressionResolver,
private val languageVersionSettings: LanguageVersionSettings private val languageVersionSettings: LanguageVersionSettings,
private val dataFlowValueFactory: DataFlowValueFactory
) { ) {
private lateinit var expressionTypingServices: ExpressionTypingServices private lateinit var expressionTypingServices: ExpressionTypingServices
@@ -343,7 +344,7 @@ class CallExpressionResolver(
private fun getSafeOrUnsafeSelectorTypeInfo(receiver: Receiver, element: CallExpressionElement, context: ExpressionTypingContext): private fun getSafeOrUnsafeSelectorTypeInfo(receiver: Receiver, element: CallExpressionElement, context: ExpressionTypingContext):
KotlinTypeInfo { KotlinTypeInfo {
var initialDataFlowInfoForArguments = context.dataFlowInfo var initialDataFlowInfoForArguments = context.dataFlowInfo
val receiverDataFlowValue = (receiver as? ReceiverValue)?.let { DataFlowValueFactory.createDataFlowValue(it, context) } val receiverDataFlowValue = (receiver as? ReceiverValue)?.let { dataFlowValueFactory.createDataFlowValue(it, context) }
val receiverCanBeNull = receiverDataFlowValue != null && val receiverCanBeNull = receiverDataFlowValue != null &&
initialDataFlowInfoForArguments.getStableNullability(receiverDataFlowValue).canBeNull() initialDataFlowInfoForArguments.getStableNullability(receiverDataFlowValue).canBeNull()
if (receiverDataFlowValue != null && element.safe) { if (receiverDataFlowValue != null && element.safe) {
@@ -42,6 +42,7 @@ import org.jetbrains.kotlin.resolve.calls.model.MutableDataFlowInfoForArguments;
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults; import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl; import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory;
import org.jetbrains.kotlin.resolve.calls.tasks.*; import org.jetbrains.kotlin.resolve.calls.tasks.*;
import org.jetbrains.kotlin.resolve.calls.tower.NewResolutionOldInference; import org.jetbrains.kotlin.resolve.calls.tower.NewResolutionOldInference;
import org.jetbrains.kotlin.resolve.calls.tower.PSICallResolver; import org.jetbrains.kotlin.resolve.calls.tower.PSICallResolver;
@@ -76,6 +77,7 @@ public class CallResolver {
private SyntheticScopes syntheticScopes; private SyntheticScopes syntheticScopes;
private NewResolutionOldInference newResolutionOldInference; private NewResolutionOldInference newResolutionOldInference;
private PSICallResolver PSICallResolver; private PSICallResolver PSICallResolver;
private final DataFlowValueFactory dataFlowValueFactory;
private final KotlinBuiltIns builtIns; private final KotlinBuiltIns builtIns;
private final LanguageVersionSettings languageVersionSettings; private final LanguageVersionSettings languageVersionSettings;
@@ -83,10 +85,12 @@ public class CallResolver {
public CallResolver( public CallResolver(
@NotNull KotlinBuiltIns builtIns, @NotNull KotlinBuiltIns builtIns,
@NotNull LanguageVersionSettings languageVersionSettings @NotNull LanguageVersionSettings languageVersionSettings,
@NotNull DataFlowValueFactory dataFlowValueFactory
) { ) {
this.builtIns = builtIns; this.builtIns = builtIns;
this.languageVersionSettings = languageVersionSettings; this.languageVersionSettings = languageVersionSettings;
this.dataFlowValueFactory = dataFlowValueFactory;
} }
// component dependency cycle // component dependency cycle
@@ -303,7 +307,7 @@ public class CallResolver {
return resolveFunctionCall( return resolveFunctionCall(
BasicCallResolutionContext.create( BasicCallResolutionContext.create(
trace, scope, call, expectedType, dataFlowInfo, ContextDependency.INDEPENDENT, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, trace, scope, call, expectedType, dataFlowInfo, ContextDependency.INDEPENDENT, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
isAnnotationContext, languageVersionSettings isAnnotationContext, languageVersionSettings, dataFlowValueFactory
) )
); );
} }
@@ -430,7 +434,8 @@ public class CallResolver {
NO_EXPECTED_TYPE, NO_EXPECTED_TYPE,
dataFlowInfo, ContextDependency.INDEPENDENT, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, dataFlowInfo, ContextDependency.INDEPENDENT, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
false, false,
languageVersionSettings); languageVersionSettings,
dataFlowValueFactory);
if (call.getCalleeExpression() == null) return checkArgumentTypesAndFail(context); if (call.getCalleeExpression() == null) return checkArgumentTypesAndFail(context);
@@ -61,7 +61,8 @@ class CandidateResolver(
private val genericCandidateResolver: GenericCandidateResolver, private val genericCandidateResolver: GenericCandidateResolver,
private val reflectionTypes: ReflectionTypes, private val reflectionTypes: ReflectionTypes,
private val additionalTypeCheckers: Iterable<AdditionalTypeChecker>, private val additionalTypeCheckers: Iterable<AdditionalTypeChecker>,
private val smartCastManager: SmartCastManager private val smartCastManager: SmartCastManager,
private val dataFlowValueFactory: DataFlowValueFactory
) { ) {
fun <D : CallableDescriptor> performResolutionForCandidateCall( fun <D : CallableDescriptor> performResolutionForCandidateCall(
context: CallCandidateResolutionContext<D>, context: CallCandidateResolutionContext<D>,
@@ -384,7 +385,7 @@ class CandidateResolver(
val spreadElement = argument.getSpreadElement() val spreadElement = argument.getSpreadElement()
if (spreadElement != null && !type.isFlexible() && type.isMarkedNullable) { if (spreadElement != null && !type.isFlexible() && type.isMarkedNullable) {
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, type, context) val dataFlowValue = dataFlowValueFactory.createDataFlowValue(expression, type, context)
val smartCastResult = SmartCastManager.checkAndRecordPossibleCast( val smartCastResult = SmartCastManager.checkAndRecordPossibleCast(
dataFlowValue, expectedType, expression, context, dataFlowValue, expectedType, expression, context,
call = null, recordExpressionType = false call = null, recordExpressionType = false
@@ -530,7 +531,7 @@ class CandidateResolver(
if (implicitInvokeCheck && call is CallForImplicitInvoke && call.isSafeCall()) { if (implicitInvokeCheck && call is CallForImplicitInvoke && call.isSafeCall()) {
val outerCallReceiver = call.outerCall.explicitReceiver val outerCallReceiver = call.outerCall.explicitReceiver
if (outerCallReceiver != call.explicitReceiver && outerCallReceiver is ReceiverValue) { if (outerCallReceiver != call.explicitReceiver && outerCallReceiver is ReceiverValue) {
val outerReceiverDataFlowValue = DataFlowValueFactory.createDataFlowValue(outerCallReceiver, this) val outerReceiverDataFlowValue = dataFlowValueFactory.createDataFlowValue(outerCallReceiver, this)
val outerReceiverNullability = dataFlowInfo.getStableNullability(outerReceiverDataFlowValue) val outerReceiverNullability = dataFlowInfo.getStableNullability(outerReceiverDataFlowValue)
if (outerReceiverNullability.canBeNull() && !TypeUtils.isNullableType(expectedReceiverParameterType)) { if (outerReceiverNullability.canBeNull() && !TypeUtils.isNullableType(expectedReceiverParameterType)) {
nullableImplicitInvokeReceiver = true nullableImplicitInvokeReceiver = true
@@ -539,7 +540,7 @@ class CandidateResolver(
} }
} }
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiverArgument, this) val dataFlowValue = dataFlowValueFactory.createDataFlowValue(receiverArgument, this)
val nullability = dataFlowInfo.getStableNullability(dataFlowValue) val nullability = dataFlowInfo.getStableNullability(dataFlowValue)
val expression = (receiverArgument as? ExpressionReceiver)?.expression val expression = (receiverArgument as? ExpressionReceiver)?.expression
if (nullability.canBeNull() && !nullability.canBeNonNull()) { if (nullability.canBeNull() && !nullability.canBeNonNull()) {
@@ -29,7 +29,8 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class DiagnosticReporterByTrackingStrategy( class DiagnosticReporterByTrackingStrategy(
val constantExpressionEvaluator: ConstantExpressionEvaluator, val constantExpressionEvaluator: ConstantExpressionEvaluator,
val context: BasicCallResolutionContext, val context: BasicCallResolutionContext,
val psiKotlinCall: PSIKotlinCall val psiKotlinCall: PSIKotlinCall,
val dataFlowValueFactory: DataFlowValueFactory
) : DiagnosticReporter { ) : DiagnosticReporter {
private val trace = context.trace as TrackingBindingTrace private val trace = context.trace as TrackingBindingTrace
private val tracingStrategy: TracingStrategy get() = psiKotlinCall.tracingStrategy private val tracingStrategy: TracingStrategy get() = psiKotlinCall.tracingStrategy
@@ -162,7 +163,7 @@ class DiagnosticReporterByTrackingStrategy(
expressionArgument.valueArgument.getArgumentExpression(), expressionArgument.valueArgument.getArgumentExpression(),
context.statementFilter context.statementFilter
) )
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(expressionArgument.receiver.receiverValue, context) val dataFlowValue = dataFlowValueFactory.createDataFlowValue(expressionArgument.receiver.receiverValue, context)
SmartCastManager.checkAndRecordPossibleCast( SmartCastManager.checkAndRecordPossibleCast(
dataFlowValue, smartCastDiagnostic.smartCastType, argumentExpression, context, call, dataFlowValue, smartCastDiagnostic.smartCastType, argumentExpression, context, call,
recordExpressionType = true recordExpressionType = true
@@ -171,7 +172,7 @@ class DiagnosticReporterByTrackingStrategy(
is ReceiverExpressionKotlinCallArgument -> { is ReceiverExpressionKotlinCallArgument -> {
trace.markAsReported() trace.markAsReported()
val receiverValue = expressionArgument.receiver.receiverValue val receiverValue = expressionArgument.receiver.receiverValue
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiverValue, context) val dataFlowValue = dataFlowValueFactory.createDataFlowValue(receiverValue, context)
SmartCastManager.checkAndRecordPossibleCast( SmartCastManager.checkAndRecordPossibleCast(
dataFlowValue, smartCastDiagnostic.smartCastType, (receiverValue as? ExpressionReceiver)?.expression, context, call, dataFlowValue, smartCastDiagnostic.smartCastType, (receiverValue as? ExpressionReceiver)?.expression, context, call,
recordExpressionType = true recordExpressionType = true
@@ -68,7 +68,8 @@ private val SPECIAL_FUNCTION_NAMES = ResolveConstruct.values().map { it.specialF
class GenericCandidateResolver( class GenericCandidateResolver(
private val argumentTypeResolver: ArgumentTypeResolver, private val argumentTypeResolver: ArgumentTypeResolver,
private val coroutineInferenceSupport: CoroutineInferenceSupport, private val coroutineInferenceSupport: CoroutineInferenceSupport,
private val languageVersionSettings: LanguageVersionSettings private val languageVersionSettings: LanguageVersionSettings,
private val dataFlowValueFactory: DataFlowValueFactory
) { ) {
fun <D : CallableDescriptor> inferTypeArguments(context: CallCandidateResolutionContext<D>): ResolutionStatus { fun <D : CallableDescriptor> inferTypeArguments(context: CallCandidateResolutionContext<D>): ResolutionStatus {
val candidateCall = context.candidateCall val candidateCall = context.candidateCall
@@ -328,7 +329,7 @@ class GenericCandidateResolver(
val deparenthesizedArgument = KtPsiUtil.getLastElementDeparenthesized(argumentExpression, context.statementFilter) val deparenthesizedArgument = KtPsiUtil.getLastElementDeparenthesized(argumentExpression, context.statementFilter)
if (deparenthesizedArgument == null || type == null) return type if (deparenthesizedArgument == null || type == null) return type
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(deparenthesizedArgument, type, context) val dataFlowValue = dataFlowValueFactory.createDataFlowValue(deparenthesizedArgument, type, context)
if (!dataFlowValue.isStable) return type if (!dataFlowValue.isStable) return type
val possibleTypes = context.dataFlowInfo.getCollectedTypes(dataFlowValue, context.languageVersionSettings) val possibleTypes = context.dataFlowInfo.getCollectedTypes(dataFlowValue, context.languageVersionSettings)
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.resolve.DeprecationResolver
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.checkers.CheckerContext import org.jetbrains.kotlin.resolve.checkers.CheckerContext
import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.types.DeferredType import org.jetbrains.kotlin.types.DeferredType
@@ -52,6 +53,9 @@ class CallCheckerContext @JvmOverloads constructor(
val isAnnotationContext: Boolean val isAnnotationContext: Boolean
get() = resolutionContext.isAnnotationContext get() = resolutionContext.isAnnotationContext
val dataFlowValueFactory: DataFlowValueFactory
get() = resolutionContext.dataFlowValueFactory
override val languageVersionSettings: LanguageVersionSettings override val languageVersionSettings: LanguageVersionSettings
get() = resolutionContext.languageVersionSettings get() = resolutionContext.languageVersionSettings
} }
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.StatementFilter; import org.jetbrains.kotlin.resolve.StatementFilter;
import org.jetbrains.kotlin.resolve.calls.model.MutableDataFlowInfoForArguments; import org.jetbrains.kotlin.resolve.calls.model.MutableDataFlowInfoForArguments;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory;
import org.jetbrains.kotlin.resolve.scopes.LexicalScope; import org.jetbrains.kotlin.resolve.scopes.LexicalScope;
import org.jetbrains.kotlin.types.KotlinType; import org.jetbrains.kotlin.types.KotlinType;
@@ -46,11 +47,12 @@ public class BasicCallResolutionContext extends CallResolutionContext<BasicCallR
boolean collectAllCandidates, boolean collectAllCandidates,
@NotNull CallPosition callPosition, @NotNull CallPosition callPosition,
@NotNull Function1<KtExpression, KtExpression> expressionContextProvider, @NotNull Function1<KtExpression, KtExpression> expressionContextProvider,
@NotNull LanguageVersionSettings languageVersionSettings @NotNull LanguageVersionSettings languageVersionSettings,
@NotNull DataFlowValueFactory dataFlowValueFactory
) { ) {
super(trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache, super(trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache,
dataFlowInfoForArguments, statementFilter, isAnnotationContext, isDebuggerContext, collectAllCandidates, dataFlowInfoForArguments, statementFilter, isAnnotationContext, isDebuggerContext, collectAllCandidates,
callPosition, expressionContextProvider, languageVersionSettings); callPosition, expressionContextProvider, languageVersionSettings, dataFlowValueFactory);
} }
@NotNull @NotNull
@@ -63,12 +65,14 @@ public class BasicCallResolutionContext extends CallResolutionContext<BasicCallR
@NotNull ContextDependency contextDependency, @NotNull ContextDependency contextDependency,
@NotNull CheckArgumentTypesMode checkArguments, @NotNull CheckArgumentTypesMode checkArguments,
boolean isAnnotationContext, boolean isAnnotationContext,
@NotNull LanguageVersionSettings languageVersionSettings @NotNull LanguageVersionSettings languageVersionSettings,
@NotNull DataFlowValueFactory dataFlowValueFactory
) { ) {
return new BasicCallResolutionContext(trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, return new BasicCallResolutionContext(trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments,
new ResolutionResultsCacheImpl(), null, new ResolutionResultsCacheImpl(), null,
StatementFilter.NONE, isAnnotationContext, false, false, StatementFilter.NONE, isAnnotationContext, false, false,
CallPosition.Unknown.INSTANCE, DEFAULT_EXPRESSION_CONTEXT_PROVIDER, languageVersionSettings); CallPosition.Unknown.INSTANCE, DEFAULT_EXPRESSION_CONTEXT_PROVIDER, languageVersionSettings,
dataFlowValueFactory);
} }
@NotNull @NotNull
@@ -80,7 +84,7 @@ public class BasicCallResolutionContext extends CallResolutionContext<BasicCallR
context.trace, context.scope, call, context.expectedType, context.dataFlowInfo, context.contextDependency, checkArguments, context.trace, context.scope, call, context.expectedType, context.dataFlowInfo, context.contextDependency, checkArguments,
context.resolutionResultsCache, dataFlowInfoForArguments, context.resolutionResultsCache, dataFlowInfoForArguments,
context.statementFilter, context.isAnnotationContext, context.isDebuggerContext, context.collectAllCandidates, context.statementFilter, context.isAnnotationContext, context.isDebuggerContext, context.collectAllCandidates,
context.callPosition, context.expressionContextProvider, context.languageVersionSettings); context.callPosition, context.expressionContextProvider, context.languageVersionSettings, context.dataFlowValueFactory);
} }
@NotNull @NotNull
@@ -102,12 +106,13 @@ public class BasicCallResolutionContext extends CallResolutionContext<BasicCallR
boolean collectAllCandidates, boolean collectAllCandidates,
@NotNull CallPosition callPosition, @NotNull CallPosition callPosition,
@NotNull Function1<KtExpression, KtExpression> expressionContextProvider, @NotNull Function1<KtExpression, KtExpression> expressionContextProvider,
@NotNull LanguageVersionSettings languageVersionSettings @NotNull LanguageVersionSettings languageVersionSettings,
@NotNull DataFlowValueFactory dataFlowValueFactory
) { ) {
return new BasicCallResolutionContext( return new BasicCallResolutionContext(
trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache, trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache,
dataFlowInfoForArguments, statementFilter, isAnnotationContext, isDebuggerContext, collectAllCandidates, dataFlowInfoForArguments, statementFilter, isAnnotationContext, isDebuggerContext, collectAllCandidates,
callPosition, expressionContextProvider, languageVersionSettings); callPosition, expressionContextProvider, languageVersionSettings, dataFlowValueFactory);
} }
@NotNull @NotNull
@@ -115,6 +120,6 @@ public class BasicCallResolutionContext extends CallResolutionContext<BasicCallR
return new BasicCallResolutionContext( return new BasicCallResolutionContext(
trace, scope, newCall, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache, trace, scope, newCall, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache,
dataFlowInfoForArguments, statementFilter, isAnnotationContext, isDebuggerContext, collectAllCandidates, dataFlowInfoForArguments, statementFilter, isAnnotationContext, isDebuggerContext, collectAllCandidates,
callPosition, expressionContextProvider, languageVersionSettings); callPosition, expressionContextProvider, languageVersionSettings, dataFlowValueFactory);
} }
} }
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.resolve.StatementFilter;
import org.jetbrains.kotlin.resolve.calls.model.MutableDataFlowInfoForArguments; import org.jetbrains.kotlin.resolve.calls.model.MutableDataFlowInfoForArguments;
import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory;
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy; import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy;
import org.jetbrains.kotlin.resolve.scopes.LexicalScope; import org.jetbrains.kotlin.resolve.scopes.LexicalScope;
import org.jetbrains.kotlin.types.KotlinType; import org.jetbrains.kotlin.types.KotlinType;
@@ -59,11 +60,12 @@ public final class CallCandidateResolutionContext<D extends CallableDescriptor>
boolean collectAllCandidates, boolean collectAllCandidates,
@NotNull CallPosition callPosition, @NotNull CallPosition callPosition,
@NotNull Function1<KtExpression, KtExpression> expressionContextProvider, @NotNull Function1<KtExpression, KtExpression> expressionContextProvider,
@NotNull LanguageVersionSettings languageVersionSettings @NotNull LanguageVersionSettings languageVersionSettings,
@NotNull DataFlowValueFactory dataFlowValueFactory
) { ) {
super(trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache, super(trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, resolutionResultsCache,
dataFlowInfoForArguments, statementFilter, isAnnotationContext, isDebuggerContext, dataFlowInfoForArguments, statementFilter, isAnnotationContext, isDebuggerContext,
collectAllCandidates, callPosition, expressionContextProvider, languageVersionSettings); collectAllCandidates, callPosition, expressionContextProvider, languageVersionSettings, dataFlowValueFactory);
this.candidateCall = candidateCall; this.candidateCall = candidateCall;
this.tracing = tracing; this.tracing = tracing;
this.candidateResolveMode = candidateResolveMode; this.candidateResolveMode = candidateResolveMode;
@@ -80,7 +82,7 @@ public final class CallCandidateResolutionContext<D extends CallableDescriptor>
context.resolutionResultsCache, context.dataFlowInfoForArguments, context.resolutionResultsCache, context.dataFlowInfoForArguments,
context.statementFilter, context.statementFilter,
candidateResolveMode, context.isAnnotationContext, context.isDebuggerContext, context.collectAllCandidates, candidateResolveMode, context.isAnnotationContext, context.isDebuggerContext, context.collectAllCandidates,
context.callPosition, context.expressionContextProvider, context.languageVersionSettings); context.callPosition, context.expressionContextProvider, context.languageVersionSettings, context.dataFlowValueFactory);
} }
@NotNull @NotNull
@@ -92,7 +94,7 @@ public final class CallCandidateResolutionContext<D extends CallableDescriptor>
context.dataFlowInfo, context.contextDependency, context.checkArguments, context.resolutionResultsCache, context.dataFlowInfo, context.contextDependency, context.checkArguments, context.resolutionResultsCache,
context.dataFlowInfoForArguments, context.statementFilter, context.dataFlowInfoForArguments, context.statementFilter,
CandidateResolveMode.FULLY, context.isAnnotationContext, context.isDebuggerContext, context.collectAllCandidates, CandidateResolveMode.FULLY, context.isAnnotationContext, context.isDebuggerContext, context.collectAllCandidates,
context.callPosition, context.expressionContextProvider, context.languageVersionSettings); context.callPosition, context.expressionContextProvider, context.languageVersionSettings, context.dataFlowValueFactory);
} }
@Override @Override
@@ -107,12 +109,13 @@ public final class CallCandidateResolutionContext<D extends CallableDescriptor>
boolean collectAllCandidates, boolean collectAllCandidates,
@NotNull CallPosition callPosition, @NotNull CallPosition callPosition,
@NotNull Function1<KtExpression, KtExpression> expressionContextProvider, @NotNull Function1<KtExpression, KtExpression> expressionContextProvider,
@NotNull LanguageVersionSettings languageVersionSettings @NotNull LanguageVersionSettings languageVersionSettings,
@NotNull DataFlowValueFactory dataFlowValueFactory
) { ) {
return new CallCandidateResolutionContext<>( return new CallCandidateResolutionContext<>(
candidateCall, tracing, trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments, candidateCall, tracing, trace, scope, call, expectedType, dataFlowInfo, contextDependency, checkArguments,
resolutionResultsCache, dataFlowInfoForArguments, statementFilter, resolutionResultsCache, dataFlowInfoForArguments, statementFilter,
candidateResolveMode, isAnnotationContext, isDebuggerContext, collectAllCandidates, callPosition, expressionContextProvider, candidateResolveMode, isAnnotationContext, isDebuggerContext, collectAllCandidates, callPosition, expressionContextProvider,
languageVersionSettings); languageVersionSettings, dataFlowValueFactory);
} }
} }
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.resolve.StatementFilter;
import org.jetbrains.kotlin.resolve.calls.model.DataFlowInfoForArgumentsImpl; import org.jetbrains.kotlin.resolve.calls.model.DataFlowInfoForArgumentsImpl;
import org.jetbrains.kotlin.resolve.calls.model.MutableDataFlowInfoForArguments; import org.jetbrains.kotlin.resolve.calls.model.MutableDataFlowInfoForArguments;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory;
import org.jetbrains.kotlin.resolve.scopes.LexicalScope; import org.jetbrains.kotlin.resolve.scopes.LexicalScope;
import org.jetbrains.kotlin.types.KotlinType; import org.jetbrains.kotlin.types.KotlinType;
@@ -55,10 +56,12 @@ public abstract class CallResolutionContext<Context extends CallResolutionContex
boolean collectAllCandidates, boolean collectAllCandidates,
@NotNull CallPosition callPosition, @NotNull CallPosition callPosition,
@NotNull Function1<KtExpression, KtExpression> expressionContextProvider, @NotNull Function1<KtExpression, KtExpression> expressionContextProvider,
@NotNull LanguageVersionSettings languageVersionSettings @NotNull LanguageVersionSettings languageVersionSettings,
@NotNull DataFlowValueFactory dataFlowValueFactory
) { ) {
super(trace, scope, expectedType, dataFlowInfo, contextDependency, resolutionResultsCache, super(trace, scope, expectedType, dataFlowInfo, contextDependency, resolutionResultsCache,
statementFilter, isAnnotationContext, isDebuggerContext, collectAllCandidates, callPosition, expressionContextProvider, languageVersionSettings); statementFilter, isAnnotationContext, isDebuggerContext, collectAllCandidates, callPosition, expressionContextProvider, languageVersionSettings,
dataFlowValueFactory);
this.call = call; this.call = call;
this.checkArguments = checkArguments; this.checkArguments = checkArguments;
if (dataFlowInfoForArguments != null) { if (dataFlowInfoForArguments != null) {
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.resolve.BindingTrace; import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.StatementFilter; import org.jetbrains.kotlin.resolve.StatementFilter;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory;
import org.jetbrains.kotlin.resolve.scopes.LexicalScope; import org.jetbrains.kotlin.resolve.scopes.LexicalScope;
import org.jetbrains.kotlin.types.KotlinType; import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.TypeUtils; import org.jetbrains.kotlin.types.TypeUtils;
@@ -64,6 +65,9 @@ public abstract class ResolutionContext<Context extends ResolutionContext<Contex
@NotNull @NotNull
public final LanguageVersionSettings languageVersionSettings; public final LanguageVersionSettings languageVersionSettings;
@NotNull
public final DataFlowValueFactory dataFlowValueFactory;
/** /**
* Used for analyzing expression in the given context. * Used for analyzing expression in the given context.
* Should be used for going through parents to find containing function, loop etc. * Should be used for going through parents to find containing function, loop etc.
@@ -89,7 +93,8 @@ public abstract class ResolutionContext<Context extends ResolutionContext<Contex
boolean collectAllCandidates, boolean collectAllCandidates,
@NotNull CallPosition callPosition, @NotNull CallPosition callPosition,
@NotNull Function1<KtExpression, KtExpression> expressionContextProvider, @NotNull Function1<KtExpression, KtExpression> expressionContextProvider,
@NotNull LanguageVersionSettings languageVersionSettings @NotNull LanguageVersionSettings languageVersionSettings,
@NotNull DataFlowValueFactory factory
) { ) {
this.trace = trace; this.trace = trace;
this.scope = scope; this.scope = scope;
@@ -104,6 +109,7 @@ public abstract class ResolutionContext<Context extends ResolutionContext<Contex
this.callPosition = callPosition; this.callPosition = callPosition;
this.expressionContextProvider = expressionContextProvider; this.expressionContextProvider = expressionContextProvider;
this.languageVersionSettings = languageVersionSettings; this.languageVersionSettings = languageVersionSettings;
this.dataFlowValueFactory = factory;
} }
protected abstract Context create( protected abstract Context create(
@@ -117,7 +123,8 @@ public abstract class ResolutionContext<Context extends ResolutionContext<Contex
boolean collectAllCandidates, boolean collectAllCandidates,
@NotNull CallPosition callPosition, @NotNull CallPosition callPosition,
@NotNull Function1<KtExpression, KtExpression> expressionContextProvider, @NotNull Function1<KtExpression, KtExpression> expressionContextProvider,
@NotNull LanguageVersionSettings languageVersionSettings @NotNull LanguageVersionSettings languageVersionSettings,
@NotNull DataFlowValueFactory dataFlowValueFactory
); );
@NotNull @NotNull
@@ -130,14 +137,14 @@ public abstract class ResolutionContext<Context extends ResolutionContext<Contex
public Context replaceBindingTrace(@NotNull BindingTrace trace) { public Context replaceBindingTrace(@NotNull BindingTrace trace) {
if (this.trace == trace) return self(); if (this.trace == trace) return self();
return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter, return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates, callPosition, expressionContextProvider, languageVersionSettings); collectAllCandidates, callPosition, expressionContextProvider, languageVersionSettings, dataFlowValueFactory);
} }
@NotNull @NotNull
public Context replaceDataFlowInfo(@NotNull DataFlowInfo newDataFlowInfo) { public Context replaceDataFlowInfo(@NotNull DataFlowInfo newDataFlowInfo) {
if (newDataFlowInfo == dataFlowInfo) return self(); if (newDataFlowInfo == dataFlowInfo) return self();
return create(trace, scope, newDataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter, return create(trace, scope, newDataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates, callPosition, expressionContextProvider, languageVersionSettings); collectAllCandidates, callPosition, expressionContextProvider, languageVersionSettings, dataFlowValueFactory);
} }
@NotNull @NotNull
@@ -145,28 +152,28 @@ public abstract class ResolutionContext<Context extends ResolutionContext<Contex
if (newExpectedType == null) return replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE); if (newExpectedType == null) return replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE);
if (expectedType == newExpectedType) return self(); if (expectedType == newExpectedType) return self();
return create(trace, scope, dataFlowInfo, newExpectedType, contextDependency, resolutionResultsCache, statementFilter, return create(trace, scope, dataFlowInfo, newExpectedType, contextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates, callPosition, expressionContextProvider, languageVersionSettings); collectAllCandidates, callPosition, expressionContextProvider, languageVersionSettings, dataFlowValueFactory);
} }
@NotNull @NotNull
public Context replaceScope(@NotNull LexicalScope newScope) { public Context replaceScope(@NotNull LexicalScope newScope) {
if (newScope == scope) return self(); if (newScope == scope) return self();
return create(trace, newScope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter, return create(trace, newScope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates, callPosition, expressionContextProvider, languageVersionSettings); collectAllCandidates, callPosition, expressionContextProvider, languageVersionSettings, dataFlowValueFactory);
} }
@NotNull @NotNull
public Context replaceContextDependency(@NotNull ContextDependency newContextDependency) { public Context replaceContextDependency(@NotNull ContextDependency newContextDependency) {
if (newContextDependency == contextDependency) return self(); if (newContextDependency == contextDependency) return self();
return create(trace, scope, dataFlowInfo, expectedType, newContextDependency, resolutionResultsCache, statementFilter, return create(trace, scope, dataFlowInfo, expectedType, newContextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates, callPosition, expressionContextProvider, languageVersionSettings); collectAllCandidates, callPosition, expressionContextProvider, languageVersionSettings, dataFlowValueFactory);
} }
@NotNull @NotNull
public Context replaceResolutionResultsCache(@NotNull ResolutionResultsCache newResolutionResultsCache) { public Context replaceResolutionResultsCache(@NotNull ResolutionResultsCache newResolutionResultsCache) {
if (newResolutionResultsCache == resolutionResultsCache) return self(); if (newResolutionResultsCache == resolutionResultsCache) return self();
return create(trace, scope, dataFlowInfo, expectedType, contextDependency, newResolutionResultsCache, statementFilter, return create(trace, scope, dataFlowInfo, expectedType, contextDependency, newResolutionResultsCache, statementFilter,
collectAllCandidates, callPosition, expressionContextProvider, languageVersionSettings); collectAllCandidates, callPosition, expressionContextProvider, languageVersionSettings, dataFlowValueFactory);
} }
@NotNull @NotNull
@@ -177,25 +184,25 @@ public abstract class ResolutionContext<Context extends ResolutionContext<Contex
@NotNull @NotNull
public Context replaceCollectAllCandidates(boolean newCollectAllCandidates) { public Context replaceCollectAllCandidates(boolean newCollectAllCandidates) {
return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter, return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
newCollectAllCandidates, callPosition, expressionContextProvider, languageVersionSettings); newCollectAllCandidates, callPosition, expressionContextProvider, languageVersionSettings, dataFlowValueFactory);
} }
@NotNull @NotNull
public Context replaceStatementFilter(@NotNull StatementFilter statementFilter) { public Context replaceStatementFilter(@NotNull StatementFilter statementFilter) {
return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter, return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates, callPosition, expressionContextProvider, languageVersionSettings); collectAllCandidates, callPosition, expressionContextProvider, languageVersionSettings, dataFlowValueFactory);
} }
@NotNull @NotNull
public Context replaceCallPosition(@NotNull CallPosition callPosition) { public Context replaceCallPosition(@NotNull CallPosition callPosition) {
return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter, return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates, callPosition, expressionContextProvider, languageVersionSettings); collectAllCandidates, callPosition, expressionContextProvider, languageVersionSettings, dataFlowValueFactory);
} }
@NotNull @NotNull
public Context replaceExpressionContextProvider(@NotNull Function1<KtExpression, KtExpression> expressionContextProvider) { public Context replaceExpressionContextProvider(@NotNull Function1<KtExpression, KtExpression> expressionContextProvider) {
return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter, return create(trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, statementFilter,
collectAllCandidates, callPosition, expressionContextProvider, languageVersionSettings); collectAllCandidates, callPosition, expressionContextProvider, languageVersionSettings, dataFlowValueFactory);
} }
@Nullable @Nullable
@@ -89,7 +89,7 @@ fun ResolvedCall<*>.getImplicitReceivers(): Collection<ReceiverValue> =
private fun ResolvedCall<*>.hasSafeNullableReceiver(context: CallResolutionContext<*>): Boolean { private fun ResolvedCall<*>.hasSafeNullableReceiver(context: CallResolutionContext<*>): Boolean {
if (!call.isSafeCall()) return false if (!call.isSafeCall()) return false
val receiverValue = getExplicitReceiverValue()?.let { DataFlowValueFactory.createDataFlowValue(it, context) } val receiverValue = getExplicitReceiverValue()?.let { context.dataFlowValueFactory.createDataFlowValue(it, context) }
?: return false ?: return false
return context.dataFlowInfo.getStableNullability(receiverValue).canBeNull() return context.dataFlowInfo.getStableNullability(receiverValue).canBeNull()
} }
@@ -50,13 +50,47 @@ import org.jetbrains.kotlin.types.isError
* This class is intended to create data flow values for different kind of expressions. * This class is intended to create data flow values for different kind of expressions.
* Then data flow values serve as keys to obtain data flow information for these expressions. * Then data flow values serve as keys to obtain data flow information for these expressions.
*/ */
object DataFlowValueFactory { interface DataFlowValueFactory {
@JvmStatic
fun createDataFlowValue( fun createDataFlowValue(
expression: KtExpression, expression: KtExpression,
type: KotlinType, type: KotlinType,
resolutionContext: ResolutionContext<*> resolutionContext: ResolutionContext<*>
): DataFlowValue
fun createDataFlowValue(
expression: KtExpression,
type: KotlinType,
bindingContext: BindingContext,
containingDeclarationOrModule: DeclarationDescriptor
): DataFlowValue
fun createDataFlowValueForStableReceiver(receiver: ReceiverValue): DataFlowValue
fun createDataFlowValue(
receiverValue: ReceiverValue,
resolutionContext: ResolutionContext<*>
): DataFlowValue
fun createDataFlowValue(
receiverValue: ReceiverValue,
bindingContext: BindingContext,
containingDeclarationOrModule: DeclarationDescriptor
): DataFlowValue
fun createDataFlowValueForProperty(
property: KtProperty,
variableDescriptor: VariableDescriptor,
bindingContext: BindingContext,
usageContainingModule: ModuleDescriptor?
): DataFlowValue
}
class DataFlowValueFactoryImpl : DataFlowValueFactory {
override fun createDataFlowValue(
expression: KtExpression,
type: KotlinType,
resolutionContext: ResolutionContext<*>
) = createDataFlowValue(expression, type, resolutionContext.trace.bindingContext, resolutionContext.scope.ownerDescriptor) ) = createDataFlowValue(expression, type, resolutionContext.trace.bindingContext, resolutionContext.scope.ownerDescriptor)
private fun isComplexExpression(expression: KtExpression): Boolean = when (expression) { private fun isComplexExpression(expression: KtExpression): Boolean = when (expression) {
@@ -69,8 +103,7 @@ object DataFlowValueFactory {
else -> false else -> false
} }
@JvmStatic override fun createDataFlowValue(
fun createDataFlowValue(
expression: KtExpression, expression: KtExpression,
type: KotlinType, type: KotlinType,
bindingContext: BindingContext, bindingContext: BindingContext,
@@ -107,17 +140,14 @@ object DataFlowValueFactory {
return DataFlowValue(if (result === IdentifierInfo.NO) ExpressionIdentifierInfo(expression) else result, type) return DataFlowValue(if (result === IdentifierInfo.NO) ExpressionIdentifierInfo(expression) else result, type)
} }
@JvmStatic override fun createDataFlowValueForStableReceiver(receiver: ReceiverValue) = DataFlowValue(IdentifierInfo.Receiver(receiver), receiver.type)
fun createDataFlowValueForStableReceiver(receiver: ReceiverValue) = DataFlowValue(IdentifierInfo.Receiver(receiver), receiver.type)
@JvmStatic override fun createDataFlowValue(
fun createDataFlowValue(
receiverValue: ReceiverValue, receiverValue: ReceiverValue,
resolutionContext: ResolutionContext<*> resolutionContext: ResolutionContext<*>
) = createDataFlowValue(receiverValue, resolutionContext.trace.bindingContext, resolutionContext.scope.ownerDescriptor) ) = createDataFlowValue(receiverValue, resolutionContext.trace.bindingContext, resolutionContext.scope.ownerDescriptor)
@JvmStatic override fun createDataFlowValue(
fun createDataFlowValue(
receiverValue: ReceiverValue, receiverValue: ReceiverValue,
bindingContext: BindingContext, bindingContext: BindingContext,
containingDeclarationOrModule: DeclarationDescriptor containingDeclarationOrModule: DeclarationDescriptor
@@ -132,8 +162,7 @@ object DataFlowValueFactory {
else -> throw UnsupportedOperationException("Unsupported receiver value: " + receiverValue::class.java.name) else -> throw UnsupportedOperationException("Unsupported receiver value: " + receiverValue::class.java.name)
} }
@JvmStatic override fun createDataFlowValueForProperty(
fun createDataFlowValueForProperty(
property: KtProperty, property: KtProperty,
variableDescriptor: VariableDescriptor, variableDescriptor: VariableDescriptor,
bindingContext: BindingContext, bindingContext: BindingContext,
@@ -351,19 +380,6 @@ object DataFlowValueFactory {
return true return true
} }
private fun propertyKind(propertyDescriptor: PropertyDescriptor, usageModule: ModuleDescriptor?): Kind {
if (propertyDescriptor.isVar) return MUTABLE_PROPERTY
if (propertyDescriptor.isOverridable) return PROPERTY_WITH_GETTER
if (!hasDefaultGetter(propertyDescriptor)) return PROPERTY_WITH_GETTER
if (!invisibleFromOtherModules(propertyDescriptor)) {
val declarationModule = DescriptorUtils.getContainingModule(propertyDescriptor)
if (usageModule == null || usageModule != declarationModule) {
return ALIEN_PUBLIC_PROPERTY
}
}
return STABLE_VALUE
}
private fun variableKind( private fun variableKind(
variableDescriptor: VariableDescriptor, variableDescriptor: VariableDescriptor,
usageModule: ModuleDescriptor?, usageModule: ModuleDescriptor?,
@@ -407,41 +423,56 @@ object DataFlowValueFactory {
CAPTURED_VARIABLE CAPTURED_VARIABLE
} }
/** companion object {
* Determines whether a variable with a given descriptor is stable or not at the given usage place. /**
* * Determines whether a variable with a given descriptor is stable or not at the given usage place.
* *
* Stable means that the variable value cannot change. The simple (non-property) variable is considered stable if it's immutable (val). *
* * Stable means that the variable value cannot change. The simple (non-property) variable is considered stable if it's immutable (val).
* *
* If the variable is a property, it's considered stable if it's immutable (val) AND it's final (not open) AND *
* the default getter is in use (otherwise nobody can guarantee that a getter is consistent) AND * If the variable is a property, it's considered stable if it's immutable (val) AND it's final (not open) AND
* (it's private OR internal OR used at the same module where it's defined). * the default getter is in use (otherwise nobody can guarantee that a getter is consistent) AND
* The last check corresponds to a risk of changing property definition in another module, e.g. from "val" to "var". * (it's private OR internal OR used at the same module where it's defined).
* The last check corresponds to a risk of changing property definition in another module, e.g. from "val" to "var".
* @param variableDescriptor descriptor of a considered variable * @param variableDescriptor descriptor of a considered variable
* * * *
* @param usageModule a module with a considered usage place, or null if it's not known (not recommended) * @param usageModule a module with a considered usage place, or null if it's not known (not recommended)
* * * *
* @return true if variable is stable, false otherwise * @return true if variable is stable, false otherwise
*/ */
fun isStableValue( fun isStableValue(
variableDescriptor: VariableDescriptor, variableDescriptor: VariableDescriptor,
usageModule: ModuleDescriptor? usageModule: ModuleDescriptor?
): Boolean { ): Boolean {
if (variableDescriptor.isVar) return false if (variableDescriptor.isVar) return false
return variableDescriptor !is PropertyDescriptor || propertyKind(variableDescriptor, usageModule) === STABLE_VALUE return variableDescriptor !is PropertyDescriptor || propertyKind(variableDescriptor, usageModule) === STABLE_VALUE
} }
private fun invisibleFromOtherModules(descriptor: DeclarationDescriptorWithVisibility): Boolean { private fun propertyKind(propertyDescriptor: PropertyDescriptor, usageModule: ModuleDescriptor?): Kind {
if (Visibilities.INVISIBLE_FROM_OTHER_MODULES.contains(descriptor.visibility)) return true if (propertyDescriptor.isVar) return MUTABLE_PROPERTY
if (propertyDescriptor.isOverridable) return PROPERTY_WITH_GETTER
if (!hasDefaultGetter(propertyDescriptor)) return PROPERTY_WITH_GETTER
if (!invisibleFromOtherModules(propertyDescriptor)) {
val declarationModule = DescriptorUtils.getContainingModule(propertyDescriptor)
if (usageModule == null || usageModule != declarationModule) {
return ALIEN_PUBLIC_PROPERTY
}
}
return STABLE_VALUE
}
val containingDeclaration = descriptor.containingDeclaration private fun hasDefaultGetter(propertyDescriptor: PropertyDescriptor): Boolean {
return containingDeclaration is DeclarationDescriptorWithVisibility && invisibleFromOtherModules(containingDeclaration) val getter = propertyDescriptor.getter
} return getter == null || getter.isDefault
}
private fun hasDefaultGetter(propertyDescriptor: PropertyDescriptor): Boolean { private fun invisibleFromOtherModules(descriptor: DeclarationDescriptorWithVisibility): Boolean {
val getter = propertyDescriptor.getter if (Visibilities.INVISIBLE_FROM_OTHER_MODULES.contains(descriptor.visibility)) return true
return getter == null || getter.isDefault
val containingDeclaration = descriptor.containingDeclaration
return containingDeclaration is DeclarationDescriptorWithVisibility && invisibleFromOtherModules(containingDeclaration)
}
} }
} }
@@ -41,10 +41,11 @@ class SmartCastManager {
bindingContext: BindingContext, bindingContext: BindingContext,
containingDeclarationOrModule: DeclarationDescriptor, containingDeclarationOrModule: DeclarationDescriptor,
dataFlowInfo: DataFlowInfo, dataFlowInfo: DataFlowInfo,
languageVersionSettings: LanguageVersionSettings languageVersionSettings: LanguageVersionSettings,
dataFlowValueFactory: DataFlowValueFactory
): List<KotlinType> { ): List<KotlinType> {
val variants = getSmartCastVariantsExcludingReceiver( val variants = getSmartCastVariantsExcludingReceiver(
bindingContext, containingDeclarationOrModule, dataFlowInfo, receiverToCast, languageVersionSettings bindingContext, containingDeclarationOrModule, dataFlowInfo, receiverToCast, languageVersionSettings, dataFlowValueFactory
) )
val result = ArrayList<KotlinType>(variants.size + 1) val result = ArrayList<KotlinType>(variants.size + 1)
result.add(receiverToCast.type) result.add(receiverToCast.type)
@@ -64,7 +65,8 @@ class SmartCastManager {
context.scope.ownerDescriptor, context.scope.ownerDescriptor,
context.dataFlowInfo, context.dataFlowInfo,
receiverToCast, receiverToCast,
context.languageVersionSettings context.languageVersionSettings,
context.dataFlowValueFactory
) )
} }
@@ -76,9 +78,10 @@ class SmartCastManager {
containingDeclarationOrModule: DeclarationDescriptor, containingDeclarationOrModule: DeclarationDescriptor,
dataFlowInfo: DataFlowInfo, dataFlowInfo: DataFlowInfo,
receiverToCast: ReceiverValue, receiverToCast: ReceiverValue,
languageVersionSettings: LanguageVersionSettings languageVersionSettings: LanguageVersionSettings,
dataFlowValueFactory: DataFlowValueFactory
): Collection<KotlinType> { ): Collection<KotlinType> {
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiverToCast, bindingContext, containingDeclarationOrModule) val dataFlowValue = dataFlowValueFactory.createDataFlowValue(receiverToCast, bindingContext, containingDeclarationOrModule)
return dataFlowInfo.getCollectedTypes(dataFlowValue, languageVersionSettings) return dataFlowInfo.getCollectedTypes(dataFlowValue, languageVersionSettings)
} }
@@ -39,6 +39,7 @@ import org.jetbrains.kotlin.resolve.calls.model.ReceiverKotlinCallArgument
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallAtom import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallAtom
import org.jetbrains.kotlin.resolve.calls.model.SimpleKotlinCallArgument import org.jetbrains.kotlin.resolve.calls.model.SimpleKotlinCallArgument
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.util.CallMaker import org.jetbrains.kotlin.resolve.calls.util.CallMaker
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
@@ -61,7 +62,8 @@ class KotlinResolutionCallbacksImpl(
val argumentTypeResolver: ArgumentTypeResolver, val argumentTypeResolver: ArgumentTypeResolver,
val languageVersionSettings: LanguageVersionSettings, val languageVersionSettings: LanguageVersionSettings,
val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer, val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer,
val constantExpressionEvaluator: ConstantExpressionEvaluator val constantExpressionEvaluator: ConstantExpressionEvaluator,
val dataFlowValueFactory: DataFlowValueFactory
) : KotlinResolutionCallbacks { ) : KotlinResolutionCallbacks {
val trace: BindingTrace = topLevelCallContext.trace val trace: BindingTrace = topLevelCallContext.trace
@@ -87,7 +89,8 @@ class KotlinResolutionCallbacksImpl(
fun createCallArgument(ktExpression: KtExpression, typeInfo: KotlinTypeInfo) = fun createCallArgument(ktExpression: KtExpression, typeInfo: KotlinTypeInfo) =
createSimplePSICallArgument( createSimplePSICallArgument(
trace.bindingContext, outerCallContext.statementFilter, outerCallContext.scope.ownerDescriptor, trace.bindingContext, outerCallContext.statementFilter, outerCallContext.scope.ownerDescriptor,
CallMaker.makeExternalValueArgument(ktExpression), DataFlowInfo.EMPTY, typeInfo, languageVersionSettings CallMaker.makeExternalValueArgument(ktExpression), DataFlowInfo.EMPTY, typeInfo, languageVersionSettings,
dataFlowValueFactory
) )
val lambdaInfo = LambdaInfo( val lambdaInfo = LambdaInfo(
@@ -168,7 +171,7 @@ class KotlinResolutionCallbacksImpl(
trace.bindingContext, trace.bindingContext,
psiKotlinCall.resultDataFlowInfo, psiKotlinCall.resultDataFlowInfo,
ExpressionReceiver.create(expression, returnType, trace.bindingContext), ExpressionReceiver.create(expression, returnType, trace.bindingContext),
languageVersionSettings languageVersionSettings, dataFlowValueFactory
) )
} }
@@ -41,6 +41,7 @@ import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.makeNullableTypeIfSafeReceiver import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.makeNullableTypeIfSafeReceiver
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
import org.jetbrains.kotlin.resolve.scopes.receivers.CastImplicitClassReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.CastImplicitClassReceiver
@@ -66,7 +67,8 @@ class KotlinToResolvedCallTransformer(
private val expressionTypingServices: ExpressionTypingServices, private val expressionTypingServices: ExpressionTypingServices,
private val doubleColonExpressionResolver: DoubleColonExpressionResolver, private val doubleColonExpressionResolver: DoubleColonExpressionResolver,
private val additionalDiagnosticReporter: AdditionalDiagnosticReporter, private val additionalDiagnosticReporter: AdditionalDiagnosticReporter,
private val moduleDescriptor: ModuleDescriptor private val moduleDescriptor: ModuleDescriptor,
private val dataFlowValueFactory: DataFlowValueFactory
) { ) {
companion object { companion object {
private val REPORT_MISSING_NEW_INFERENCE_DIAGNOSTIC private val REPORT_MISSING_NEW_INFERENCE_DIAGNOSTIC
@@ -99,7 +101,7 @@ class KotlinToResolvedCallTransformer(
val resultSubstitutor = baseResolvedCall.constraintSystem.buildResultingSubstitutor() val resultSubstitutor = baseResolvedCall.constraintSystem.buildResultingSubstitutor()
val ktPrimitiveCompleter = ResolvedAtomCompleter( val ktPrimitiveCompleter = ResolvedAtomCompleter(
resultSubstitutor, context.trace, context, this, expressionTypingServices, argumentTypeResolver, resultSubstitutor, context.trace, context, this, expressionTypingServices, argumentTypeResolver,
doubleColonExpressionResolver, deprecationResolver, moduleDescriptor doubleColonExpressionResolver, deprecationResolver, moduleDescriptor, dataFlowValueFactory
) )
for (subKtPrimitive in candidate.subResolvedAtoms) { for (subKtPrimitive in candidate.subResolvedAtoms) {
@@ -347,7 +349,7 @@ class KotlinToResolvedCallTransformer(
val trackingTrace = TrackingBindingTrace(trace) val trackingTrace = TrackingBindingTrace(trace)
val newContext = context.replaceBindingTrace(trackingTrace) val newContext = context.replaceBindingTrace(trackingTrace)
val diagnosticReporter = val diagnosticReporter =
DiagnosticReporterByTrackingStrategy(constantExpressionEvaluator, newContext, completedCallAtom.atom.psiKotlinCall) DiagnosticReporterByTrackingStrategy(constantExpressionEvaluator, newContext, completedCallAtom.atom.psiKotlinCall, context.dataFlowValueFactory)
val diagnosticHolder = KotlinDiagnosticsHolder.SimpleHolder() val diagnosticHolder = KotlinDiagnosticsHolder.SimpleHolder()
additionalDiagnosticReporter.reportAdditionalDiagnostics(completedCallAtom, resultingDescriptor, diagnosticHolder, diagnostics) additionalDiagnosticReporter.reportAdditionalDiagnostics(completedCallAtom, resultingDescriptor, diagnosticHolder, diagnostics)
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.scopes.receivers.* import org.jetbrains.kotlin.resolve.scopes.receivers.*
import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.UnwrappedType
@@ -210,7 +211,8 @@ internal fun createSimplePSICallArgument(
contextForArgument.trace.bindingContext, contextForArgument.statementFilter, contextForArgument.trace.bindingContext, contextForArgument.statementFilter,
contextForArgument.scope.ownerDescriptor, valueArgument, contextForArgument.scope.ownerDescriptor, valueArgument,
contextForArgument.dataFlowInfo, typeInfoForArgument, contextForArgument.dataFlowInfo, typeInfoForArgument,
contextForArgument.languageVersionSettings contextForArgument.languageVersionSettings,
contextForArgument.dataFlowValueFactory
) )
internal fun createSimplePSICallArgument( internal fun createSimplePSICallArgument(
@@ -220,7 +222,8 @@ internal fun createSimplePSICallArgument(
valueArgument: ValueArgument, valueArgument: ValueArgument,
dataFlowInfoBeforeThisArgument: DataFlowInfo, dataFlowInfoBeforeThisArgument: DataFlowInfo,
typeInfoForArgument: KotlinTypeInfo, typeInfoForArgument: KotlinTypeInfo,
languageVersionSettings: LanguageVersionSettings languageVersionSettings: LanguageVersionSettings,
dataFlowValueFactory: DataFlowValueFactory
): SimplePSIKotlinCallArgument? { ): SimplePSIKotlinCallArgument? {
val ktExpression = KtPsiUtil.getLastElementDeparenthesized(valueArgument.getArgumentExpression(), statementFilter) ?: return null val ktExpression = KtPsiUtil.getLastElementDeparenthesized(valueArgument.getArgumentExpression(), statementFilter) ?: return null
@@ -235,7 +238,8 @@ internal fun createSimplePSICallArgument(
ownerDescriptor, bindingContext, ownerDescriptor, bindingContext,
typeInfoForArgument.dataFlowInfo, // dataFlowInfoBeforeThisArgument cannot be used here, because of if() { if (x != null) return; x } typeInfoForArgument.dataFlowInfo, // dataFlowInfoBeforeThisArgument cannot be used here, because of if() { if (x != null) return; x }
ExpressionReceiver.create(ktExpression, baseType, bindingContext), ExpressionReceiver.create(ktExpression, baseType, bindingContext),
languageVersionSettings languageVersionSettings,
dataFlowValueFactory
).let { ).let {
if (onlyResolvedCall == null) it.prepareReceiverRegardingCaptureTypes() else it if (onlyResolvedCall == null) it.prepareReceiverRegardingCaptureTypes() else it
} }
@@ -528,16 +528,17 @@ class NewResolutionOldInference(
} }
fun ResolutionContext<*>.transformToReceiverWithSmartCastInfo(receiver: ReceiverValue) = fun ResolutionContext<*>.transformToReceiverWithSmartCastInfo(receiver: ReceiverValue) =
transformToReceiverWithSmartCastInfo(scope.ownerDescriptor, trace.bindingContext, dataFlowInfo, receiver, languageVersionSettings) transformToReceiverWithSmartCastInfo(scope.ownerDescriptor, trace.bindingContext, dataFlowInfo, receiver, languageVersionSettings, dataFlowValueFactory)
fun transformToReceiverWithSmartCastInfo( fun transformToReceiverWithSmartCastInfo(
containingDescriptor: DeclarationDescriptor, containingDescriptor: DeclarationDescriptor,
bindingContext: BindingContext, bindingContext: BindingContext,
dataFlowInfo: DataFlowInfo, dataFlowInfo: DataFlowInfo,
receiver: ReceiverValue, receiver: ReceiverValue,
languageVersionSettings: LanguageVersionSettings languageVersionSettings: LanguageVersionSettings,
dataFlowValueFactory: DataFlowValueFactory
): ReceiverValueWithSmartCastInfo { ): ReceiverValueWithSmartCastInfo {
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiver, bindingContext, containingDescriptor) val dataFlowValue = dataFlowValueFactory.createDataFlowValue(receiver, bindingContext, containingDescriptor)
return ReceiverValueWithSmartCastInfo( return ReceiverValueWithSmartCastInfo(
receiver, receiver,
dataFlowInfo.getCollectedTypes(dataFlowValue, languageVersionSettings), dataFlowInfo.getCollectedTypes(dataFlowValue, languageVersionSettings),
@@ -61,7 +61,8 @@ class PSICallResolver(
private val typeApproximator: TypeApproximator, private val typeApproximator: TypeApproximator,
private val argumentTypeResolver: ArgumentTypeResolver, private val argumentTypeResolver: ArgumentTypeResolver,
private val effectSystem: EffectSystem, private val effectSystem: EffectSystem,
private val constantExpressionEvaluator: ConstantExpressionEvaluator private val constantExpressionEvaluator: ConstantExpressionEvaluator,
private val dataFlowValueFactory: DataFlowValueFactory
) { ) {
private val GIVEN_CANDIDATES_NAME = Name.special("<given candidates>") private val GIVEN_CANDIDATES_NAME = Name.special("<given candidates>")
@@ -152,7 +153,7 @@ class PSICallResolver(
KotlinResolutionCallbacksImpl( KotlinResolutionCallbacksImpl(
context, expressionTypingServices, typeApproximator, context, expressionTypingServices, typeApproximator,
argumentTypeResolver, languageVersionSettings, kotlinToResolvedCallTransformer, argumentTypeResolver, languageVersionSettings, kotlinToResolvedCallTransformer,
constantExpressionEvaluator constantExpressionEvaluator, dataFlowValueFactory
) )
private fun calculateExpectedType(context: BasicCallResolutionContext): UnwrappedType? { private fun calculateExpectedType(context: BasicCallResolutionContext): UnwrappedType? {
@@ -423,7 +424,7 @@ class PSICallResolver(
temporaryTrace.record(BindingContext.REFERENCE_TARGET, calleeExpression, variable.resolvedCall.candidateDescriptor) temporaryTrace.record(BindingContext.REFERENCE_TARGET, calleeExpression, variable.resolvedCall.candidateDescriptor)
val dataFlowValue = val dataFlowValue =
DataFlowValueFactory.createDataFlowValue(variableReceiver, temporaryTrace.bindingContext, context.scope.ownerDescriptor) dataFlowValueFactory.createDataFlowValue(variableReceiver, temporaryTrace.bindingContext, context.scope.ownerDescriptor)
return ReceiverValueWithSmartCastInfo( return ReceiverValueWithSmartCastInfo(
variableReceiver, variableReceiver,
context.dataFlowInfo.getCollectedTypes(dataFlowValue, context.languageVersionSettings), context.dataFlowInfo.getCollectedTypes(dataFlowValue, context.languageVersionSettings),
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor
import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategyImpl import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategyImpl
import org.jetbrains.kotlin.resolve.calls.util.CallMaker import org.jetbrains.kotlin.resolve.calls.util.CallMaker
@@ -44,7 +45,8 @@ class ResolvedAtomCompleter(
private val argumentTypeResolver: ArgumentTypeResolver, private val argumentTypeResolver: ArgumentTypeResolver,
private val doubleColonExpressionResolver: DoubleColonExpressionResolver, private val doubleColonExpressionResolver: DoubleColonExpressionResolver,
deprecationResolver: DeprecationResolver, deprecationResolver: DeprecationResolver,
moduleDescriptor: ModuleDescriptor moduleDescriptor: ModuleDescriptor,
private val dataFlowValueFactory: DataFlowValueFactory
) { ) {
private val callCheckerContext = CallCheckerContext(topLevelCallContext, deprecationResolver, moduleDescriptor) private val callCheckerContext = CallCheckerContext(topLevelCallContext, deprecationResolver, moduleDescriptor)
@@ -83,7 +83,7 @@ object PrimitiveNumericComparisonCallChecker : CallChecker {
private fun CallCheckerContext.getStableTypesForExpression(expression: KtExpression): List<KotlinType> { private fun CallCheckerContext.getStableTypesForExpression(expression: KtExpression): List<KotlinType> {
val type = trace.bindingContext.getType(expression) ?: return emptyList() val type = trace.bindingContext.getType(expression) ?: return emptyList()
val dataFlowValue = DataFlowValueFactory.createDataFlowValue( val dataFlowValue = dataFlowValueFactory.createDataFlowValue(
expression, type, trace.bindingContext, resolutionContext.scope.ownerDescriptor expression, type, trace.bindingContext, resolutionContext.scope.ownerDescriptor
) )
val dataFlowInfo = trace.get(BindingContext.EXPRESSION_TYPE_INFO, expression)?.dataFlowInfo ?: return emptyList() val dataFlowInfo = trace.get(BindingContext.EXPRESSION_TYPE_INFO, expression)?.dataFlowInfo ?: return emptyList()
@@ -55,7 +55,6 @@ import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl;
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsUtil; import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsUtil;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory;
import org.jetbrains.kotlin.resolve.calls.smartcasts.Nullability; import org.jetbrains.kotlin.resolve.calls.smartcasts.Nullability;
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind; import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind;
import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionCandidate; import org.jetbrains.kotlin.resolve.calls.tasks.ResolutionCandidate;
@@ -87,7 +86,6 @@ import static org.jetbrains.kotlin.lexer.KtTokens.*;
import static org.jetbrains.kotlin.resolve.BindingContext.*; import static org.jetbrains.kotlin.resolve.BindingContext.*;
import static org.jetbrains.kotlin.resolve.calls.context.ContextDependency.DEPENDENT; import static org.jetbrains.kotlin.resolve.calls.context.ContextDependency.DEPENDENT;
import static org.jetbrains.kotlin.resolve.calls.context.ContextDependency.INDEPENDENT; import static org.jetbrains.kotlin.resolve.calls.context.ContextDependency.INDEPENDENT;
import static org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory.createDataFlowValue;
import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE; import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE;
import static org.jetbrains.kotlin.types.TypeUtils.noExpectedType; import static org.jetbrains.kotlin.types.TypeUtils.noExpectedType;
import static org.jetbrains.kotlin.types.expressions.ControlStructureTypingUtils.createCallForSpecialConstruction; import static org.jetbrains.kotlin.types.expressions.ControlStructureTypingUtils.createCallForSpecialConstruction;
@@ -139,14 +137,14 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
return false; return false;
} }
private static void checkNull( private void checkNull(
@NotNull KtSimpleNameExpression expression, @NotNull KtSimpleNameExpression expression,
@NotNull ExpressionTypingContext context, @NotNull ExpressionTypingContext context,
@Nullable KotlinType type @Nullable KotlinType type
) { ) {
// Receivers are normally analyzed at resolve, with an exception of KT-10175 // Receivers are normally analyzed at resolve, with an exception of KT-10175
if (type != null && !KotlinTypeKt.isError(type) && !isLValueOrUnsafeReceiver(expression)) { if (type != null && !KotlinTypeKt.isError(type) && !isLValueOrUnsafeReceiver(expression)) {
DataFlowValue dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, type, context); DataFlowValue dataFlowValue = components.dataFlowValueFactory.createDataFlowValue(expression, type, context);
Nullability nullability = context.dataFlowInfo.getStableNullability(dataFlowValue); Nullability nullability = context.dataFlowInfo.getStableNullability(dataFlowValue);
if (!nullability.canBeNonNull() && nullability.canBeNull()) { if (!nullability.canBeNonNull() && nullability.canBeNull()) {
if (isDangerousWithNull(expression, context)) { if (isDangerousWithNull(expression, context)) {
@@ -182,8 +180,8 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
KotlinTypeInfo result = facade.getTypeInfo(innerExpression, context); KotlinTypeInfo result = facade.getTypeInfo(innerExpression, context);
KotlinType resultType = result.getType(); KotlinType resultType = result.getType();
if (resultType != null) { if (resultType != null) {
DataFlowValue innerValue = DataFlowValueFactory.createDataFlowValue(innerExpression, resultType, context); DataFlowValue innerValue = components.dataFlowValueFactory.createDataFlowValue(innerExpression, resultType, context);
DataFlowValue resultValue = DataFlowValueFactory.createDataFlowValue(expression, resultType, context); DataFlowValue resultValue = components.dataFlowValueFactory.createDataFlowValue(expression, resultType, context);
result = result.replaceDataFlowInfo(result.getDataFlowInfo().assign(resultValue, innerValue, result = result.replaceDataFlowInfo(result.getDataFlowInfo().assign(resultValue, innerValue,
components.languageVersionSettings)); components.languageVersionSettings));
} }
@@ -321,7 +319,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
checkBinaryWithTypeRHS(expression, context, targetType, subjectType); checkBinaryWithTypeRHS(expression, context, targetType, subjectType);
DataFlowInfo dataFlowInfo = typeInfo.getDataFlowInfo(); DataFlowInfo dataFlowInfo = typeInfo.getDataFlowInfo();
if (operationType == AS_KEYWORD) { if (operationType == AS_KEYWORD) {
DataFlowValue value = createDataFlowValue(left, subjectType, context); DataFlowValue value = components.dataFlowValueFactory.createDataFlowValue(left, subjectType, context);
typeInfo = typeInfo.replaceDataFlowInfo(dataFlowInfo.establishSubtyping(value, targetType, typeInfo = typeInfo.replaceDataFlowInfo(dataFlowInfo.establishSubtyping(value, targetType,
components.languageVersionSettings)); components.languageVersionSettings));
} }
@@ -789,7 +787,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
checkLValue(context.trace, context, baseExpression, stubExpression, expression); checkLValue(context.trace, context, baseExpression, stubExpression, expression);
} }
// x++ type is x type, but ++x type is x.inc() type // x++ type is x type, but ++x type is x.inc() type
DataFlowValue receiverValue = DataFlowValueFactory.createDataFlowValue( DataFlowValue receiverValue = components.dataFlowValueFactory.createDataFlowValue(
(ReceiverValue) call.getExplicitReceiver(), contextWithExpectedType); (ReceiverValue) call.getExplicitReceiver(), contextWithExpectedType);
if (expression instanceof KtPrefixExpression) { if (expression instanceof KtPrefixExpression) {
result = returnType; result = returnType;
@@ -797,7 +795,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
else { else {
result = receiverType; result = receiverType;
// Also record data flow information for x++ value (= x) // Also record data flow information for x++ value (= x)
DataFlowValue returnValue = DataFlowValueFactory.createDataFlowValue(expression, receiverType, contextWithExpectedType); DataFlowValue returnValue = components.dataFlowValueFactory.createDataFlowValue(expression, receiverType, contextWithExpectedType);
typeInfo = typeInfo.replaceDataFlowInfo(typeInfo.getDataFlowInfo().assign(returnValue, receiverValue, typeInfo = typeInfo.replaceDataFlowInfo(typeInfo.getDataFlowInfo().assign(returnValue, receiverValue,
components.languageVersionSettings)); components.languageVersionSettings));
} }
@@ -854,7 +852,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
context.trace.report(UNNECESSARY_NOT_NULL_ASSERTION.on(operationSign, TypeUtils.makeNotNullable(baseType))); context.trace.report(UNNECESSARY_NOT_NULL_ASSERTION.on(operationSign, TypeUtils.makeNotNullable(baseType)));
} }
else { else {
DataFlowValue value = createDataFlowValue(baseExpression, baseType, context); DataFlowValue value = components.dataFlowValueFactory.createDataFlowValue(baseExpression, baseType, context);
baseTypeInfo = baseTypeInfo.replaceDataFlowInfo(dataFlowInfo.disequate(value, DataFlowValue.nullValue(components.builtIns), baseTypeInfo = baseTypeInfo.replaceDataFlowInfo(dataFlowInfo.disequate(value, DataFlowValue.nullValue(components.builtIns),
components.languageVersionSettings)); components.languageVersionSettings));
} }
@@ -896,7 +894,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
} }
// Returns `true` if warnings should be reported for left-hand side of elvis and not-null (!!) assertion // Returns `true` if warnings should be reported for left-hand side of elvis and not-null (!!) assertion
private static boolean isKnownToBeNotNull( private boolean isKnownToBeNotNull(
@NotNull KtExpression expression, @NotNull KtExpression expression,
@Nullable KotlinType ktType, @Nullable KotlinType ktType,
@NotNull ExpressionTypingContext context @NotNull ExpressionTypingContext context
@@ -907,7 +905,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
if (!TypeUtils.isNullableType(ktType)) return true; if (!TypeUtils.isNullableType(ktType)) return true;
DataFlowValue dataFlowValue = createDataFlowValue(expression, ktType, context); DataFlowValue dataFlowValue = components.dataFlowValueFactory.createDataFlowValue(expression, ktType, context);
return context.dataFlowInfo.getStableNullability(dataFlowValue) == Nullability.NOT_NULL; return context.dataFlowInfo.getStableNullability(dataFlowValue) == Nullability.NOT_NULL;
} }
@@ -1287,7 +1285,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
leftType == null && KotlinBuiltIns.isNothing(rightType)) return TypeInfoFactoryKt.noTypeInfo(dataFlowInfo); leftType == null && KotlinBuiltIns.isNothing(rightType)) return TypeInfoFactoryKt.noTypeInfo(dataFlowInfo);
if (leftType != null) { if (leftType != null) {
DataFlowValue leftValue = createDataFlowValue(left, leftType, context); DataFlowValue leftValue = components.dataFlowValueFactory.createDataFlowValue(left, leftType, context);
DataFlowInfo rightDataFlowInfo = resolvedCall.getDataFlowInfoForArguments().getResultInfo(); DataFlowInfo rightDataFlowInfo = resolvedCall.getDataFlowInfoForArguments().getResultInfo();
boolean jumpInRight = KotlinBuiltIns.isNothing(rightType); boolean jumpInRight = KotlinBuiltIns.isNothing(rightType);
DataFlowValue nullValue = DataFlowValue.nullValue(components.builtIns); DataFlowValue nullValue = DataFlowValue.nullValue(components.builtIns);
@@ -1299,12 +1297,12 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
components.languageVersionSettings); components.languageVersionSettings);
} }
} }
DataFlowValue resultValue = DataFlowValueFactory.createDataFlowValue(expression, type, context); DataFlowValue resultValue = components.dataFlowValueFactory.createDataFlowValue(expression, type, context);
dataFlowInfo = dataFlowInfo =
dataFlowInfo.assign(resultValue, leftValue, components.languageVersionSettings) dataFlowInfo.assign(resultValue, leftValue, components.languageVersionSettings)
.disequate(resultValue, nullValue, components.languageVersionSettings); .disequate(resultValue, nullValue, components.languageVersionSettings);
if (!jumpInRight) { if (!jumpInRight) {
DataFlowValue rightValue = DataFlowValueFactory.createDataFlowValue(right, rightType, context); DataFlowValue rightValue = components.dataFlowValueFactory.createDataFlowValue(right, rightType, context);
rightDataFlowInfo = rightDataFlowInfo.assign(resultValue, rightValue, components.languageVersionSettings); rightDataFlowInfo = rightDataFlowInfo.assign(resultValue, rightValue, components.languageVersionSettings);
dataFlowInfo = dataFlowInfo.or(rightDataFlowInfo); dataFlowInfo = dataFlowInfo.or(rightDataFlowInfo);
} }
@@ -1327,7 +1325,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
} }
@NotNull @NotNull
private static DataFlowInfo establishSubtypingForTypeRHS( private DataFlowInfo establishSubtypingForTypeRHS(
@NotNull KtBinaryExpressionWithTypeRHS left, @NotNull KtBinaryExpressionWithTypeRHS left,
@NotNull DataFlowInfo dataFlowInfo, @NotNull DataFlowInfo dataFlowInfo,
@NotNull ExpressionTypingContext context, @NotNull ExpressionTypingContext context,
@@ -1338,7 +1336,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
KtExpression underSafeAs = left.getLeft(); KtExpression underSafeAs = left.getLeft();
KotlinType underSafeAsType = context.trace.getType(underSafeAs); KotlinType underSafeAsType = context.trace.getType(underSafeAs);
if (underSafeAsType != null) { if (underSafeAsType != null) {
DataFlowValue underSafeAsValue = createDataFlowValue(underSafeAs, underSafeAsType, context); DataFlowValue underSafeAsValue = components.dataFlowValueFactory.createDataFlowValue(underSafeAs, underSafeAsType, context);
KotlinType targetType = context.trace.get(BindingContext.TYPE, left.getRight()); KotlinType targetType = context.trace.get(BindingContext.TYPE, left.getRight());
if (targetType != null) { if (targetType != null) {
return dataFlowInfo.establishSubtyping(underSafeAsValue, targetType, languageVersionSettings); return dataFlowInfo.establishSubtyping(underSafeAsValue, targetType, languageVersionSettings);
@@ -185,10 +185,10 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor {
DataFlowInfo thenDataFlowInfo = thenTypeInfo.getDataFlowInfo(); DataFlowInfo thenDataFlowInfo = thenTypeInfo.getDataFlowInfo();
DataFlowInfo elseDataFlowInfo = elseTypeInfo.getDataFlowInfo(); DataFlowInfo elseDataFlowInfo = elseTypeInfo.getDataFlowInfo();
if (resultType != null && thenType != null && elseType != null) { if (resultType != null && thenType != null && elseType != null) {
DataFlowValue resultValue = DataFlowValueFactory.createDataFlowValue(ifExpression, resultType, context); DataFlowValue resultValue = components.dataFlowValueFactory.createDataFlowValue(ifExpression, resultType, context);
DataFlowValue thenValue = DataFlowValueFactory.createDataFlowValue(thenBranch, thenType, context); DataFlowValue thenValue = components.dataFlowValueFactory.createDataFlowValue(thenBranch, thenType, context);
thenDataFlowInfo = thenDataFlowInfo.assign(resultValue, thenValue, components.languageVersionSettings); thenDataFlowInfo = thenDataFlowInfo.assign(resultValue, thenValue, components.languageVersionSettings);
DataFlowValue elseValue = DataFlowValueFactory.createDataFlowValue(elseBranch, elseType, context); DataFlowValue elseValue = components.dataFlowValueFactory.createDataFlowValue(elseBranch, elseType, context);
elseDataFlowInfo = elseDataFlowInfo.assign(resultValue, elseValue, components.languageVersionSettings); elseDataFlowInfo = elseDataFlowInfo.assign(resultValue, elseValue, components.languageVersionSettings);
} }
@@ -60,6 +60,7 @@ public class DataFlowAnalyzer {
private final ExpressionTypingFacade facade; private final ExpressionTypingFacade facade;
private final LanguageVersionSettings languageVersionSettings; private final LanguageVersionSettings languageVersionSettings;
private final EffectSystem effectSystem; private final EffectSystem effectSystem;
private final DataFlowValueFactory dataFlowValueFactory;
public DataFlowAnalyzer( public DataFlowAnalyzer(
@NotNull Iterable<AdditionalTypeChecker> additionalTypeCheckers, @NotNull Iterable<AdditionalTypeChecker> additionalTypeCheckers,
@@ -68,7 +69,8 @@ public class DataFlowAnalyzer {
@NotNull KotlinBuiltIns builtIns, @NotNull KotlinBuiltIns builtIns,
@NotNull ExpressionTypingFacade facade, @NotNull ExpressionTypingFacade facade,
@NotNull LanguageVersionSettings languageVersionSettings, @NotNull LanguageVersionSettings languageVersionSettings,
@NotNull EffectSystem effectSystem @NotNull EffectSystem effectSystem,
@NotNull DataFlowValueFactory factory
) { ) {
this.additionalTypeCheckers = additionalTypeCheckers; this.additionalTypeCheckers = additionalTypeCheckers;
this.constantExpressionEvaluator = constantExpressionEvaluator; this.constantExpressionEvaluator = constantExpressionEvaluator;
@@ -77,11 +79,12 @@ public class DataFlowAnalyzer {
this.facade = facade; this.facade = facade;
this.languageVersionSettings = languageVersionSettings; this.languageVersionSettings = languageVersionSettings;
this.effectSystem = effectSystem; this.effectSystem = effectSystem;
this.dataFlowValueFactory = factory;
} }
// NB: use this method only for functions from 'Any' // NB: use this method only for functions from 'Any'
@Nullable @Nullable
private static FunctionDescriptor getOverriddenDescriptorFromClass(@NotNull FunctionDescriptor descriptor) { private FunctionDescriptor getOverriddenDescriptorFromClass(@NotNull FunctionDescriptor descriptor) {
if (descriptor.getKind() != CallableMemberDescriptor.Kind.FAKE_OVERRIDE) return descriptor; if (descriptor.getKind() != CallableMemberDescriptor.Kind.FAKE_OVERRIDE) return descriptor;
Collection<? extends FunctionDescriptor> overriddenDescriptors = descriptor.getOverriddenDescriptors(); Collection<? extends FunctionDescriptor> overriddenDescriptors = descriptor.getOverriddenDescriptors();
if (overriddenDescriptors.isEmpty()) return descriptor; if (overriddenDescriptors.isEmpty()) return descriptor;
@@ -95,7 +98,7 @@ public class DataFlowAnalyzer {
return null; return null;
} }
private static boolean typeHasOverriddenEquals(@NotNull KotlinType type, @NotNull KtElement lookupElement) { private boolean typeHasOverriddenEquals(@NotNull KotlinType type, @NotNull KtElement lookupElement) {
Collection<SimpleFunctionDescriptor> members = type.getMemberScope().getContributedFunctions( Collection<SimpleFunctionDescriptor> members = type.getMemberScope().getContributedFunctions(
OperatorNameConventions.EQUALS, new KotlinLookupLocation(lookupElement)); OperatorNameConventions.EQUALS, new KotlinLookupLocation(lookupElement));
for (FunctionDescriptor member : members) { for (FunctionDescriptor member : members) {
@@ -114,7 +117,7 @@ public class DataFlowAnalyzer {
} }
// Returns true if we can prove that 'type' has equals method from 'Any' base type // Returns true if we can prove that 'type' has equals method from 'Any' base type
public static boolean typeHasEqualsFromAny(@NotNull KotlinType type, @NotNull KtElement lookupElement) { public boolean typeHasEqualsFromAny(@NotNull KotlinType type, @NotNull KtElement lookupElement) {
TypeConstructor constructor = type.getConstructor(); TypeConstructor constructor = type.getConstructor();
// Subtypes can override equals for non-final types // Subtypes can override equals for non-final types
if (!constructor.isFinal()) return false; if (!constructor.isFinal()) return false;
@@ -171,8 +174,8 @@ public class DataFlowAnalyzer {
KotlinType rhsType = context.trace.getBindingContext().getType(right); KotlinType rhsType = context.trace.getBindingContext().getType(right);
if (rhsType == null) return; if (rhsType == null) return;
DataFlowValue leftValue = DataFlowValueFactory.createDataFlowValue(left, lhsType, context); DataFlowValue leftValue = dataFlowValueFactory.createDataFlowValue(left, lhsType, context);
DataFlowValue rightValue = DataFlowValueFactory.createDataFlowValue(right, rhsType, context); DataFlowValue rightValue = dataFlowValueFactory.createDataFlowValue(right, rhsType, context);
Boolean equals = null; Boolean equals = null;
if (operationToken == KtTokens.EQEQ || operationToken == KtTokens.EQEQEQ) { if (operationToken == KtTokens.EQEQ || operationToken == KtTokens.EQEQEQ) {
@@ -338,12 +341,12 @@ public class DataFlowAnalyzer {
} }
@Nullable @Nullable
public static SmartCastResult checkPossibleCast( public SmartCastResult checkPossibleCast(
@NotNull KotlinType expressionType, @NotNull KotlinType expressionType,
@NotNull KtExpression expression, @NotNull KtExpression expression,
@NotNull ResolutionContext c @NotNull ResolutionContext c
) { ) {
DataFlowValue dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, expressionType, c); DataFlowValue dataFlowValue = dataFlowValueFactory.createDataFlowValue(expression, expressionType, c);
return SmartCastManager.Companion.checkAndRecordPossibleCast(dataFlowValue, c.expectedType, expression, c, null, false); return SmartCastManager.Companion.checkAndRecordPossibleCast(dataFlowValue, c.expectedType, expression, c, null, false);
} }
@@ -366,7 +369,7 @@ public class DataFlowAnalyzer {
} }
@NotNull @NotNull
public static KotlinTypeInfo illegalStatementType(@NotNull KtExpression expression, @NotNull ExpressionTypingContext context, @NotNull ExpressionTypingInternals facade) { public KotlinTypeInfo illegalStatementType(@NotNull KtExpression expression, @NotNull ExpressionTypingContext context, @NotNull ExpressionTypingInternals facade) {
facade.checkStatementType( facade.checkStatementType(
expression, context.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT)); expression, context.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT));
context.trace.report(EXPRESSION_EXPECTED.on(expression, expression)); context.trace.report(EXPRESSION_EXPECTED.on(expression, expression));
@@ -379,7 +382,7 @@ public class DataFlowAnalyzer {
@NotNull KotlinType type, @NotNull KotlinType type,
@NotNull ResolutionContext c @NotNull ResolutionContext c
) { ) {
DataFlowValue dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, type, c); DataFlowValue dataFlowValue = c.dataFlowValueFactory.createDataFlowValue(expression, type, c);
return getAllPossibleTypes(type, c, dataFlowValue, c.languageVersionSettings); return getAllPossibleTypes(type, c, dataFlowValue, c.languageVersionSettings);
} }
@@ -93,7 +93,8 @@ class DoubleColonExpressionResolver(
val reflectionTypes: ReflectionTypes, val reflectionTypes: ReflectionTypes,
val typeResolver: TypeResolver, val typeResolver: TypeResolver,
val languageVersionSettings: LanguageVersionSettings, val languageVersionSettings: LanguageVersionSettings,
val additionalCheckers: Iterable<ClassLiteralChecker> val additionalCheckers: Iterable<ClassLiteralChecker>,
val dataFlowValueFactory: DataFlowValueFactory
) { ) {
private lateinit var expressionTypingServices: ExpressionTypingServices private lateinit var expressionTypingServices: ExpressionTypingServices
@@ -112,7 +113,7 @@ class DoubleColonExpressionResolver(
if (result != null && !result.type.isError) { if (result != null && !result.type.isError) {
val inherentType = result.type val inherentType = result.type
val dataFlowInfo = (result as? DoubleColonLHS.Expression)?.dataFlowInfo ?: c.dataFlowInfo val dataFlowInfo = (result as? DoubleColonLHS.Expression)?.dataFlowInfo ?: c.dataFlowInfo
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression.receiverExpression!!, inherentType, c) val dataFlowValue = dataFlowValueFactory.createDataFlowValue(expression.receiverExpression!!, inherentType, c)
val type = val type =
if (!dataFlowInfo.getStableNullability(dataFlowValue).canBeNull()) inherentType.makeNotNullable() if (!dataFlowInfo.getStableNullability(dataFlowValue).canBeNull()) inherentType.makeNotNullable()
else inherentType else inherentType
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.resolve.calls.CallExpressionResolver;
import org.jetbrains.kotlin.resolve.calls.CallResolver; import org.jetbrains.kotlin.resolve.calls.CallResolver;
import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker; import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker;
import org.jetbrains.kotlin.resolve.calls.checkers.RttiExpressionChecker; import org.jetbrains.kotlin.resolve.calls.checkers.RttiExpressionChecker;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory;
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator; import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
import org.jetbrains.kotlin.types.WrappedTypeFactory; import org.jetbrains.kotlin.types.WrappedTypeFactory;
@@ -70,6 +71,7 @@ public class ExpressionTypingComponents {
/*package*/ DeprecationResolver deprecationResolver; /*package*/ DeprecationResolver deprecationResolver;
/*package*/ EffectSystem effectSystem; /*package*/ EffectSystem effectSystem;
/*package*/ ContractParsingServices contractParsingServices; /*package*/ ContractParsingServices contractParsingServices;
/*package*/ DataFlowValueFactory dataFlowValueFactory;
@Inject @Inject
public void setGlobalContext(@NotNull GlobalContext globalContext) { public void setGlobalContext(@NotNull GlobalContext globalContext) {
@@ -240,4 +242,9 @@ public class ExpressionTypingComponents {
public void setContractParsingServices(@NotNull ContractParsingServices contractParsingServices) { public void setContractParsingServices(@NotNull ContractParsingServices contractParsingServices) {
this.contractParsingServices = contractParsingServices; this.contractParsingServices = contractParsingServices;
} }
@Inject
public void setDataFlowValueFactory(@NotNull DataFlowValueFactory dataFlowValueFactory) {
this.dataFlowValueFactory = dataFlowValueFactory;
}
} }
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.StatementFilter; import org.jetbrains.kotlin.resolve.StatementFilter;
import org.jetbrains.kotlin.resolve.calls.context.*; import org.jetbrains.kotlin.resolve.calls.context.*;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory;
import org.jetbrains.kotlin.resolve.scopes.LexicalScope; import org.jetbrains.kotlin.resolve.scopes.LexicalScope;
import org.jetbrains.kotlin.types.KotlinType; import org.jetbrains.kotlin.types.KotlinType;
@@ -35,9 +36,10 @@ public class ExpressionTypingContext extends ResolutionContext<ExpressionTypingC
@NotNull LexicalScope scope, @NotNull LexicalScope scope,
@NotNull DataFlowInfo dataFlowInfo, @NotNull DataFlowInfo dataFlowInfo,
@NotNull KotlinType expectedType, @NotNull KotlinType expectedType,
@NotNull LanguageVersionSettings languageVersionSettings @NotNull LanguageVersionSettings languageVersionSettings,
@NotNull DataFlowValueFactory dataFlowValueFactory
) { ) {
return newContext(trace, scope, dataFlowInfo, expectedType, ContextDependency.INDEPENDENT, StatementFilter.NONE, languageVersionSettings); return newContext(trace, scope, dataFlowInfo, expectedType, ContextDependency.INDEPENDENT, StatementFilter.NONE, languageVersionSettings, dataFlowValueFactory);
} }
@NotNull @NotNull
@@ -48,10 +50,11 @@ public class ExpressionTypingContext extends ResolutionContext<ExpressionTypingC
@NotNull KotlinType expectedType, @NotNull KotlinType expectedType,
@NotNull ContextDependency contextDependency, @NotNull ContextDependency contextDependency,
@NotNull StatementFilter statementFilter, @NotNull StatementFilter statementFilter,
@NotNull LanguageVersionSettings languageVersionSettings @NotNull LanguageVersionSettings languageVersionSettings,
@NotNull DataFlowValueFactory dataFlowValueFactory
) { ) {
return newContext(trace, scope, dataFlowInfo, expectedType, contextDependency, return newContext(trace, scope, dataFlowInfo, expectedType, contextDependency,
new ResolutionResultsCacheImpl(), statementFilter, false, languageVersionSettings); new ResolutionResultsCacheImpl(), statementFilter, false, languageVersionSettings, dataFlowValueFactory);
} }
@NotNull @NotNull
@@ -61,7 +64,8 @@ public class ExpressionTypingContext extends ResolutionContext<ExpressionTypingC
context.contextDependency, context.resolutionResultsCache, context.contextDependency, context.resolutionResultsCache,
context.statementFilter, context.statementFilter,
context.isAnnotationContext, context.isDebuggerContext, context.collectAllCandidates, context.isAnnotationContext, context.isDebuggerContext, context.collectAllCandidates,
context.callPosition, context.expressionContextProvider, context.languageVersionSettings); context.callPosition, context.expressionContextProvider, context.languageVersionSettings,
context.dataFlowValueFactory);
} }
@NotNull @NotNull
@@ -72,7 +76,8 @@ public class ExpressionTypingContext extends ResolutionContext<ExpressionTypingC
context.statementFilter, context.statementFilter,
context.isAnnotationContext, isDebuggerContext, context.collectAllCandidates, context.isAnnotationContext, isDebuggerContext, context.collectAllCandidates,
context.callPosition, context.expressionContextProvider, context.callPosition, context.expressionContextProvider,
context.languageVersionSettings); context.languageVersionSettings,
context.dataFlowValueFactory);
} }
@NotNull @NotNull
@@ -85,12 +90,13 @@ public class ExpressionTypingContext extends ResolutionContext<ExpressionTypingC
@NotNull ResolutionResultsCache resolutionResultsCache, @NotNull ResolutionResultsCache resolutionResultsCache,
@NotNull StatementFilter statementFilter, @NotNull StatementFilter statementFilter,
boolean isAnnotationContext, boolean isAnnotationContext,
@NotNull LanguageVersionSettings languageVersionSettings @NotNull LanguageVersionSettings languageVersionSettings,
@NotNull DataFlowValueFactory dataFlowValueFactory
) { ) {
return new ExpressionTypingContext( return new ExpressionTypingContext(
trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache, trace, scope, dataFlowInfo, expectedType, contextDependency, resolutionResultsCache,
statementFilter, isAnnotationContext, false, false, statementFilter, isAnnotationContext, false, false,
CallPosition.Unknown.INSTANCE, DEFAULT_EXPRESSION_CONTEXT_PROVIDER, languageVersionSettings); CallPosition.Unknown.INSTANCE, DEFAULT_EXPRESSION_CONTEXT_PROVIDER, languageVersionSettings, dataFlowValueFactory);
} }
private ExpressionTypingContext( private ExpressionTypingContext(
@@ -106,11 +112,12 @@ public class ExpressionTypingContext extends ResolutionContext<ExpressionTypingC
boolean collectAllCandidates, boolean collectAllCandidates,
@NotNull CallPosition callPosition, @NotNull CallPosition callPosition,
@NotNull Function1<KtExpression, KtExpression> expressionContextProvider, @NotNull Function1<KtExpression, KtExpression> expressionContextProvider,
@NotNull LanguageVersionSettings languageVersionSettings @NotNull LanguageVersionSettings languageVersionSettings,
@NotNull DataFlowValueFactory dataFlowValueFactory
) { ) {
super(trace, scope, expectedType, dataFlowInfo, contextDependency, resolutionResultsCache, super(trace, scope, expectedType, dataFlowInfo, contextDependency, resolutionResultsCache,
statementFilter, isAnnotationContext, isDebuggerContext, collectAllCandidates, callPosition, expressionContextProvider, statementFilter, isAnnotationContext, isDebuggerContext, collectAllCandidates, callPosition, expressionContextProvider,
languageVersionSettings); languageVersionSettings, dataFlowValueFactory);
} }
@Override @Override
@@ -125,12 +132,13 @@ public class ExpressionTypingContext extends ResolutionContext<ExpressionTypingC
boolean collectAllCandidates, boolean collectAllCandidates,
@NotNull CallPosition callPosition, @NotNull CallPosition callPosition,
@NotNull Function1<KtExpression, KtExpression> expressionContextProvider, @NotNull Function1<KtExpression, KtExpression> expressionContextProvider,
@NotNull LanguageVersionSettings languageVersionSettings @NotNull LanguageVersionSettings languageVersionSettings,
@NotNull DataFlowValueFactory dataFlowValueFactory
) { ) {
return new ExpressionTypingContext(trace, scope, dataFlowInfo, return new ExpressionTypingContext(trace, scope, dataFlowInfo,
expectedType, contextDependency, resolutionResultsCache, expectedType, contextDependency, resolutionResultsCache,
statementFilter, isAnnotationContext, isDebuggerContext, statementFilter, isAnnotationContext, isDebuggerContext,
collectAllCandidates, callPosition, expressionContextProvider, collectAllCandidates, callPosition, expressionContextProvider,
languageVersionSettings); languageVersionSettings, dataFlowValueFactory);
} }
} }
@@ -32,7 +32,6 @@ import org.jetbrains.kotlin.resolve.calls.context.ContextDependency;
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext; import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory;
import org.jetbrains.kotlin.resolve.scopes.LexicalScope; import org.jetbrains.kotlin.resolve.scopes.LexicalScope;
import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind; import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind;
import org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope; import org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope;
@@ -115,7 +114,8 @@ public class ExpressionTypingServices {
@NotNull ContextDependency contextDependency @NotNull ContextDependency contextDependency
) { ) {
ExpressionTypingContext context = ExpressionTypingContext.newContext( ExpressionTypingContext context = ExpressionTypingContext.newContext(
trace, scope, dataFlowInfo, expectedType, contextDependency, statementFilter, getLanguageVersionSettings() trace, scope, dataFlowInfo, expectedType, contextDependency, statementFilter, getLanguageVersionSettings(),
expressionTypingComponents.dataFlowValueFactory
); );
if (contextExpression != expression) { if (contextExpression != expression) {
context = context.replaceExpressionContextProvider(arg -> arg == expression ? contextExpression : null); context = context.replaceExpressionContextProvider(arg -> arg == expression ? contextExpression : null);
@@ -157,7 +157,8 @@ public class ExpressionTypingServices {
} }
checkFunctionReturnType(function, ExpressionTypingContext.newContext( checkFunctionReturnType(function, ExpressionTypingContext.newContext(
trace, trace,
functionInnerScope, dataFlowInfo, expectedReturnType != null ? expectedReturnType : NO_EXPECTED_TYPE, getLanguageVersionSettings() functionInnerScope, dataFlowInfo, expectedReturnType != null ? expectedReturnType : NO_EXPECTED_TYPE, getLanguageVersionSettings(),
expressionTypingComponents.dataFlowValueFactory
)); ));
} }
@@ -225,7 +226,8 @@ public class ExpressionTypingServices {
expressionTypingComponents.overloadChecker); expressionTypingComponents.overloadChecker);
ExpressionTypingContext context = ExpressionTypingContext.newContext( ExpressionTypingContext context = ExpressionTypingContext.newContext(
trace, functionInnerScope, dataFlowInfo, NO_EXPECTED_TYPE, getLanguageVersionSettings() trace, functionInnerScope, dataFlowInfo, NO_EXPECTED_TYPE, getLanguageVersionSettings(),
expressionTypingComponents.dataFlowValueFactory
); );
KotlinTypeInfo typeInfo = expressionTypingFacade.getTypeInfo(bodyExpression, context, function.hasBlockBody()); KotlinTypeInfo typeInfo = expressionTypingFacade.getTypeInfo(bodyExpression, context, function.hasBlockBody());
@@ -285,9 +287,9 @@ public class ExpressionTypingServices {
statementExpression, newContext.replaceExpectedType(context.expectedType), coercionStrategyForLastExpression, statementExpression, newContext.replaceExpectedType(context.expectedType), coercionStrategyForLastExpression,
blockLevelVisitor); blockLevelVisitor);
if (result.getType() != null && statementExpression.getParent() instanceof KtBlockExpression) { if (result.getType() != null && statementExpression.getParent() instanceof KtBlockExpression) {
DataFlowValue lastExpressionValue = DataFlowValueFactory.createDataFlowValue( DataFlowValue lastExpressionValue = expressionTypingComponents.dataFlowValueFactory.createDataFlowValue(
statementExpression, result.getType(), context); statementExpression, result.getType(), context);
DataFlowValue blockExpressionValue = DataFlowValueFactory.createDataFlowValue( DataFlowValue blockExpressionValue = expressionTypingComponents.dataFlowValueFactory.createDataFlowValue(
(KtBlockExpression) statementExpression.getParent(), result.getType(), context); (KtBlockExpression) statementExpression.getParent(), result.getType(), context);
result = result.replaceDataFlowInfo(result.getDataFlowInfo().assign(blockExpressionValue, lastExpressionValue, result = result.replaceDataFlowInfo(result.getDataFlowInfo().assign(blockExpressionValue, lastExpressionValue,
expressionTypingComponents.languageVersionSettings)); expressionTypingComponents.languageVersionSettings));
@@ -352,8 +352,8 @@ public class ExpressionTypingVisitorForStatements extends ExpressionTypingVisito
dataFlowInfo = resultInfo.getDataFlowInfo(); dataFlowInfo = resultInfo.getDataFlowInfo();
KotlinType rightType = resultInfo.getType(); KotlinType rightType = resultInfo.getType();
if (left != null && expectedType != null && rightType != null) { if (left != null && expectedType != null && rightType != null) {
DataFlowValue leftValue = DataFlowValueFactory.createDataFlowValue(left, expectedType, context); DataFlowValue leftValue = components.dataFlowValueFactory.createDataFlowValue(left, expectedType, context);
DataFlowValue rightValue = DataFlowValueFactory.createDataFlowValue(right, rightType, context); DataFlowValue rightValue = components.dataFlowValueFactory.createDataFlowValue(right, rightType, context);
// We cannot say here anything new about rightValue except it has the same value as leftValue // We cannot say here anything new about rightValue except it has the same value as leftValue
resultInfo = resultInfo.replaceDataFlowInfo(dataFlowInfo.assign(leftValue, rightValue, components.languageVersionSettings)); resultInfo = resultInfo.replaceDataFlowInfo(dataFlowInfo.assign(leftValue, rightValue, components.languageVersionSettings));
} }
@@ -32,7 +32,6 @@ import org.jetbrains.kotlin.resolve.calls.context.ContextDependency.INDEPENDENT
import org.jetbrains.kotlin.resolve.calls.smartcasts.ConditionalDataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.ConditionalDataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.util.CallMaker import org.jetbrains.kotlin.resolve.calls.util.CallMaker
import org.jetbrains.kotlin.resolve.checkers.PrimitiveNumericComparisonCallChecker import org.jetbrains.kotlin.resolve.checkers.PrimitiveNumericComparisonCallChecker
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
@@ -53,7 +52,7 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
val knownType = typeInfo.type val knownType = typeInfo.type
val typeReference = expression.typeReference val typeReference = expression.typeReference
if (typeReference != null && knownType != null) { if (typeReference != null && knownType != null) {
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(leftHandSide, knownType, context) val dataFlowValue = components.dataFlowValueFactory.createDataFlowValue(leftHandSide, knownType, context)
val conditionInfo = checkTypeForIs(context, expression, expression.isNegated, knownType, typeReference, dataFlowValue).thenInfo val conditionInfo = checkTypeForIs(context, expression, expression.isNegated, knownType, typeReference, dataFlowValue).thenInfo
val newDataFlowInfo = conditionInfo.and(typeInfo.dataFlowInfo) val newDataFlowInfo = conditionInfo.and(typeInfo.dataFlowInfo)
context.trace.record(BindingContext.DATAFLOW_INFO_AFTER_CONDITION, expression, newDataFlowInfo) context.trace.record(BindingContext.DATAFLOW_INFO_AFTER_CONDITION, expression, newDataFlowInfo)
@@ -104,7 +103,7 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
val subjectType = subjectTypeInfo?.type ?: ErrorUtils.createErrorType("Unknown type") val subjectType = subjectTypeInfo?.type ?: ErrorUtils.createErrorType("Unknown type")
val jumpOutPossibleInSubject: Boolean = subjectTypeInfo?.jumpOutPossible ?: false val jumpOutPossibleInSubject: Boolean = subjectTypeInfo?.jumpOutPossible ?: false
val subjectDataFlowValue = subjectExpression?.let { val subjectDataFlowValue = subjectExpression?.let {
DataFlowValueFactory.createDataFlowValue(it, subjectType, contextAfterSubject) facade.components.dataFlowValueFactory.createDataFlowValue(it, subjectType, contextAfterSubject)
} ?: DataFlowValue.nullValue(components.builtIns) } ?: DataFlowValue.nullValue(components.builtIns)
val possibleTypesForSubject = subjectTypeInfo?.dataFlowInfo?.getStableTypes( val possibleTypesForSubject = subjectTypeInfo?.dataFlowInfo?.getStableTypes(
@@ -114,7 +113,7 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
val dataFlowInfoForEntries = analyzeConditionsInWhenEntries(expression, contextAfterSubject, subjectDataFlowValue, subjectType) val dataFlowInfoForEntries = analyzeConditionsInWhenEntries(expression, contextAfterSubject, subjectDataFlowValue, subjectType)
val whenReturnType = inferTypeForWhenExpression(expression, contextWithExpectedType, contextAfterSubject, dataFlowInfoForEntries) val whenReturnType = inferTypeForWhenExpression(expression, contextWithExpectedType, contextAfterSubject, dataFlowInfoForEntries)
val whenResultValue = whenReturnType?.let { DataFlowValueFactory.createDataFlowValue(expression, it, contextAfterSubject) } val whenResultValue = whenReturnType?.let { facade.components.dataFlowValueFactory.createDataFlowValue(expression, it, contextAfterSubject) }
val branchesTypeInfo = val branchesTypeInfo =
joinWhenExpressionBranches(expression, contextAfterSubject, whenReturnType, jumpOutPossibleInSubject, whenResultValue) joinWhenExpressionBranches(expression, contextAfterSubject, whenReturnType, jumpOutPossibleInSubject, whenResultValue)
@@ -223,7 +222,7 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
val entryDataFlowInfo = val entryDataFlowInfo =
if (whenResultValue != null && entryType != null) { if (whenResultValue != null && entryType != null) {
val entryValue = DataFlowValueFactory.createDataFlowValue(entryExpression, entryType, contextAfterSubject) val entryValue = facade.components.dataFlowValueFactory.createDataFlowValue(entryExpression, entryType, contextAfterSubject)
entryTypeInfo.dataFlowInfo.assign(whenResultValue, entryValue, components.languageVersionSettings) entryTypeInfo.dataFlowInfo.assign(whenResultValue, entryValue, components.languageVersionSettings)
} else { } else {
entryTypeInfo.dataFlowInfo entryTypeInfo.dataFlowInfo
@@ -288,7 +287,7 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
): Boolean { ): Boolean {
val trace = TemporaryBindingTrace.create(contextBeforeSubject.trace, "Temporary trace for when subject nullability") val trace = TemporaryBindingTrace.create(contextBeforeSubject.trace, "Temporary trace for when subject nullability")
val subjectContext = contextBeforeSubject.replaceExpectedType(expectedType).replaceBindingTrace(trace) val subjectContext = contextBeforeSubject.replaceExpectedType(expectedType).replaceBindingTrace(trace)
val castResult = DataFlowAnalyzer.checkPossibleCast( val castResult = facade.components.dataFlowAnalyzer.checkPossibleCast(
subjectType, KtPsiUtil.safeDeparenthesize(subjectExpression), subjectContext subjectType, KtPsiUtil.safeDeparenthesize(subjectExpression), subjectContext
) )
if (castResult != null && castResult.isCorrect) { if (castResult != null && castResult.isCorrect) {
@@ -428,7 +427,7 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
} }
checkTypeCompatibility(newContext, type, subjectType, expression) checkTypeCompatibility(newContext, type, subjectType, expression)
val expressionDataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, type, newContext) val expressionDataFlowValue = facade.components.dataFlowValueFactory.createDataFlowValue(expression, type, newContext)
val subjectStableTypes = val subjectStableTypes =
listOf(subjectType) + context.dataFlowInfo.getStableTypes(subjectDataFlowValue, components.languageVersionSettings) listOf(subjectType) + context.dataFlowInfo.getStableTypes(subjectDataFlowValue, components.languageVersionSettings)
@@ -445,7 +444,7 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
return ConditionalDataFlowInfo( return ConditionalDataFlowInfo(
result.thenInfo.equate( result.thenInfo.equate(
subjectDataFlowValue, expressionDataFlowValue, subjectDataFlowValue, expressionDataFlowValue,
identityEquals = DataFlowAnalyzer.typeHasEqualsFromAny(subjectType, expression), identityEquals = facade.components.dataFlowAnalyzer.typeHasEqualsFromAny(subjectType, expression),
languageVersionSettings = components.languageVersionSettings languageVersionSettings = components.languageVersionSettings
), ),
result.elseInfo.disequate( result.elseInfo.disequate(
@@ -49,7 +49,7 @@ object SenselessComparisonChecker {
if (type == null || type.isError) return if (type == null || type.isError) return
val operationSign = expression.operationReference val operationSign = expression.operationReference
val value = DataFlowValueFactory.createDataFlowValue(expr, type, context) val value = context.dataFlowValueFactory.createDataFlowValue(expr, type, context)
val equality = val equality =
operationSign.getReferencedNameElementType() == KtTokens.EQEQ || operationSign.getReferencedNameElementType() == KtTokens.EQEQEQ operationSign.getReferencedNameElementType() == KtTokens.EQEQ || operationSign.getReferencedNameElementType() == KtTokens.EQEQEQ
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.DescriptorResolver import org.jetbrains.kotlin.resolve.DescriptorResolver
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil
import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.resolve.scopes.LexicalScope
@@ -35,7 +36,8 @@ import org.jetbrains.kotlin.types.isError
class ValueParameterResolver( class ValueParameterResolver(
private val expressionTypingServices: ExpressionTypingServices, private val expressionTypingServices: ExpressionTypingServices,
private val constantExpressionEvaluator: ConstantExpressionEvaluator, private val constantExpressionEvaluator: ConstantExpressionEvaluator,
private val languageVersionSettings: LanguageVersionSettings private val languageVersionSettings: LanguageVersionSettings,
private val dataFlowValueFactory: DataFlowValueFactory
) { ) {
fun resolveValueParameters( fun resolveValueParameters(
valueParameters: List<KtParameter>, valueParameters: List<KtParameter>,
@@ -49,7 +51,7 @@ class ValueParameterResolver(
val contextForDefaultValue = ExpressionTypingContext.newContext( val contextForDefaultValue = ExpressionTypingContext.newContext(
trace, scopeForDefaultValue, dataFlowInfo, TypeUtils.NO_EXPECTED_TYPE, trace, scopeForDefaultValue, dataFlowInfo, TypeUtils.NO_EXPECTED_TYPE,
languageVersionSettings languageVersionSettings, dataFlowValueFactory
) )
for ((descriptor, parameter) in valueParameterDescriptors.zip(valueParameters)) { for ((descriptor, parameter) in valueParameterDescriptors.zip(valueParameters)) {
@@ -33,6 +33,8 @@ import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults; import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfoFactory; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfoFactory;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactoryImpl;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt; import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil; import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil;
import org.jetbrains.kotlin.resolve.scopes.ImportingScope; import org.jetbrains.kotlin.resolve.scopes.ImportingScope;
@@ -154,7 +156,7 @@ public class ExpectedResolveDataUtil {
LanguageVersionSettings languageVersionSettings = CommonConfigurationKeysKt.getLanguageVersionSettings(environment.getConfiguration()); LanguageVersionSettings languageVersionSettings = CommonConfigurationKeysKt.getLanguageVersionSettings(environment.getConfiguration());
ExpressionTypingContext context = ExpressionTypingContext.newContext( ExpressionTypingContext context = ExpressionTypingContext.newContext(
new BindingTraceContext(), lexicalScope, new BindingTraceContext(), lexicalScope,
DataFlowInfoFactory.EMPTY, TypeUtils.NO_EXPECTED_TYPE, languageVersionSettings); DataFlowInfoFactory.EMPTY, TypeUtils.NO_EXPECTED_TYPE, languageVersionSettings, new DataFlowValueFactoryImpl());
KtExpression callElement = KtPsiFactory(project).createExpression(name); KtExpression callElement = KtPsiFactory(project).createExpression(name);
@@ -34,6 +34,7 @@ import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DeprecationResolver import org.jetbrains.kotlin.resolve.DeprecationResolver
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastManager import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastManager
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
import org.jetbrains.kotlin.resolve.scopes.* import org.jetbrains.kotlin.resolve.scopes.*
@@ -182,7 +183,8 @@ class ReferenceVariantsHelper(
bindingContext, bindingContext,
containingDeclaration, containingDeclaration,
dataFlowInfo, dataFlowInfo,
resolutionFacade.frontendService<LanguageVersionSettings>() resolutionFacade.frontendService<LanguageVersionSettings>(),
resolutionFacade.frontendService<DataFlowValueFactory>()
) )
}.toSet() }.toSet()
@@ -246,7 +246,8 @@ fun CallTypeAndReceiver<*, *>.receiverTypesWithIndex(
is DoubleColonLHS.Expression -> { is DoubleColonLHS.Expression -> {
val receiverValue = ExpressionReceiver.create(receiver, lhs.type, bindingContext) val receiverValue = ExpressionReceiver.create(receiver, lhs.type, bindingContext)
return receiverValueTypes(receiverValue, lhs.dataFlowInfo, bindingContext, return receiverValueTypes(receiverValue, lhs.dataFlowInfo, bindingContext,
moduleDescriptor, stableSmartCastsOnly, languageVersionSettings) moduleDescriptor, stableSmartCastsOnly, languageVersionSettings,
resolutionFacade.frontendService<DataFlowValueFactory>())
.map { ReceiverType(it, 0) } .map { ReceiverType(it, 0) }
} }
} }
@@ -304,7 +305,8 @@ fun CallTypeAndReceiver<*, *>.receiverTypesWithIndex(
var receiverIndex = 0 var receiverIndex = 0
fun addReceiverType(receiverValue: ReceiverValue, implicit: Boolean) { fun addReceiverType(receiverValue: ReceiverValue, implicit: Boolean) {
val types = receiverValueTypes(receiverValue, dataFlowInfo, bindingContext, moduleDescriptor, stableSmartCastsOnly, languageVersionSettings) val types = receiverValueTypes(receiverValue, dataFlowInfo, bindingContext, moduleDescriptor, stableSmartCastsOnly, languageVersionSettings,
resolutionFacade.frontendService<DataFlowValueFactory>())
types.mapTo(result) { ReceiverType(it, receiverIndex, implicit) } types.mapTo(result) { ReceiverType(it, receiverIndex, implicit) }
receiverIndex++ receiverIndex++
} }
@@ -323,16 +325,18 @@ private fun receiverValueTypes(
bindingContext: BindingContext, bindingContext: BindingContext,
moduleDescriptor: ModuleDescriptor, moduleDescriptor: ModuleDescriptor,
stableSmartCastsOnly: Boolean, stableSmartCastsOnly: Boolean,
languageVersionSettings: LanguageVersionSettings languageVersionSettings: LanguageVersionSettings,
dataFlowValueFactory: DataFlowValueFactory
): List<KotlinType> { ): List<KotlinType> {
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiverValue, bindingContext, moduleDescriptor) val dataFlowValue = dataFlowValueFactory.createDataFlowValue(receiverValue, bindingContext, moduleDescriptor)
return if (dataFlowValue.isStable || !stableSmartCastsOnly) { // we don't include smart cast receiver types for "unstable" 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( SmartCastManager().getSmartCastVariantsWithLessSpecificExcluded(
receiverValue, receiverValue,
bindingContext, bindingContext,
moduleDescriptor, moduleDescriptor,
dataFlowInfo, dataFlowInfo,
languageVersionSettings languageVersionSettings,
dataFlowValueFactory
) )
} }
else { else {
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.resolve.calls.CallResolver
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.scopes.ExplicitImportsScope import org.jetbrains.kotlin.resolve.scopes.ExplicitImportsScope
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
@@ -207,7 +208,8 @@ class ShadowedDeclarationsFilter(
val dataFlowInfo = bindingContext.getDataFlowInfoBefore(context) val dataFlowInfo = bindingContext.getDataFlowInfoBefore(context)
val context = BasicCallResolutionContext.create(bindingTrace, scope, newCall, TypeUtils.NO_EXPECTED_TYPE, dataFlowInfo, val context = BasicCallResolutionContext.create(bindingTrace, scope, newCall, TypeUtils.NO_EXPECTED_TYPE, dataFlowInfo,
ContextDependency.INDEPENDENT, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, ContextDependency.INDEPENDENT, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
false, /* languageVersionSettings */ resolutionFacade.frontendService()) false, /* languageVersionSettings */ resolutionFacade.frontendService(),
resolutionFacade.frontendService<DataFlowValueFactory>())
val callResolver = resolutionFacade.frontendService<CallResolver>() val callResolver = resolutionFacade.frontendService<CallResolver>()
val results = if (isFunction) callResolver.resolveFunctionCall(context) else callResolver.resolveSimpleProperty(context) val results = if (isFunction) callResolver.resolveFunctionCall(context) else callResolver.resolveSimpleProperty(context)
val resultingDescriptors = results.resultingCalls.map { it.resultingDescriptor } val resultingDescriptors = results.resultingCalls.map { it.resultingDescriptor }
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastManager import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastManager
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.types.FlexibleType import org.jetbrains.kotlin.types.FlexibleType
@@ -59,9 +60,10 @@ fun SmartCastManager.getSmartCastVariantsWithLessSpecificExcluded(
bindingContext: BindingContext, bindingContext: BindingContext,
containingDeclarationOrModule: DeclarationDescriptor, containingDeclarationOrModule: DeclarationDescriptor,
dataFlowInfo: DataFlowInfo, dataFlowInfo: DataFlowInfo,
languageVersionSettings: LanguageVersionSettings languageVersionSettings: LanguageVersionSettings,
dataFlowValueFactory: DataFlowValueFactory
): List<KotlinType> { ): List<KotlinType> {
val variants = getSmartCastVariants(receiverToCast, bindingContext, containingDeclarationOrModule, dataFlowInfo, languageVersionSettings) val variants = getSmartCastVariants(receiverToCast, bindingContext, containingDeclarationOrModule, dataFlowInfo, languageVersionSettings, dataFlowValueFactory)
return variants.filter { type -> return variants.filter { type ->
variants.all { another -> another === type || chooseMoreSpecific(type, another).let { it == null || it === type } } variants.all { another -> another === type || chooseMoreSpecific(type, another).let { it == null || it === type } }
} }
@@ -57,6 +57,7 @@ import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfoFactory import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfoFactory
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.util.CallMaker import org.jetbrains.kotlin.resolve.calls.util.CallMaker
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
@@ -338,6 +339,7 @@ object IDELightClassContexts {
private val codegenAffectingAnnotations: CodegenAffectingAnnotations, private val codegenAffectingAnnotations: CodegenAffectingAnnotations,
private val callResolver: CallResolver, private val callResolver: CallResolver,
private val languageVersionSettings: LanguageVersionSettings, private val languageVersionSettings: LanguageVersionSettings,
private val dataFlowValueFactory: DataFlowValueFactory,
constantExpressionEvaluator: ConstantExpressionEvaluator, constantExpressionEvaluator: ConstantExpressionEvaluator,
storageManager: StorageManager storageManager: StorageManager
) : AnnotationResolverImpl(callResolver, constantExpressionEvaluator, storageManager) { ) : AnnotationResolverImpl(callResolver, constantExpressionEvaluator, storageManager) {
@@ -361,7 +363,8 @@ object IDELightClassContexts {
BasicCallResolutionContext.create( BasicCallResolutionContext.create(
trace, scope, CallMaker.makeCall(null, null, annotationEntry), TypeUtils.NO_EXPECTED_TYPE, trace, scope, CallMaker.makeCall(null, null, annotationEntry), TypeUtils.NO_EXPECTED_TYPE,
DataFlowInfoFactory.EMPTY, ContextDependency.INDEPENDENT, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, DataFlowInfoFactory.EMPTY, ContextDependency.INDEPENDENT, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
true, languageVersionSettings true, languageVersionSettings,
dataFlowValueFactory
), ),
annotationEntry.calleeExpression!!.constructorReferenceExpression!!, annotationEntry.calleeExpression!!.constructorReferenceExpression!!,
annotationConstructor.returnType annotationConstructor.returnType
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtPsiFactory import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.resolve.BindingTraceContext import org.jetbrains.kotlin.resolve.BindingTraceContext
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.resolve.scopes.utils.collectFunctions import org.jetbrains.kotlin.resolve.scopes.utils.collectFunctions
@@ -40,7 +41,8 @@ import java.util.*
class IterableTypesDetection( class IterableTypesDetection(
private val project: Project, private val project: Project,
private val forLoopConventionsChecker: ForLoopConventionsChecker, private val forLoopConventionsChecker: ForLoopConventionsChecker,
private val languageVersionSettings: LanguageVersionSettings private val languageVersionSettings: LanguageVersionSettings,
private val dataFlowValueFactory: DataFlowValueFactory
) { ) {
companion object { companion object {
private val iteratorName = Name.identifier("iterator") private val iteratorName = Name.identifier("iterator")
@@ -78,7 +80,7 @@ class IterableTypesDetection(
val expression = KtPsiFactory(project).createExpression("fake") val expression = KtPsiFactory(project).createExpression("fake")
val context = ExpressionTypingContext.newContext( val context = ExpressionTypingContext.newContext(
BindingTraceContext(), scope, DataFlowInfo.EMPTY, TypeUtils.NO_EXPECTED_TYPE, languageVersionSettings) BindingTraceContext(), scope, DataFlowInfo.EMPTY, TypeUtils.NO_EXPECTED_TYPE, languageVersionSettings, dataFlowValueFactory)
val expressionReceiver = ExpressionReceiver.create(expression, type.type, context.trace.bindingContext) val expressionReceiver = ExpressionReceiver.create(expression, type.type, context.trace.bindingContext)
val elementType = forLoopConventionsChecker.checkIterableConvention(expressionReceiver, context) val elementType = forLoopConventionsChecker.checkIterableConvention(expressionReceiver, context)
return elementType?.let { it.toFuzzyType(type.freeParameters) } return elementType?.let { it.toFuzzyType(type.freeParameters) }
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.resolve.frontendService
import org.jetbrains.kotlin.idea.util.getImplicitReceiversWithInstance import org.jetbrains.kotlin.idea.util.getImplicitReceiversWithInstance
import org.jetbrains.kotlin.idea.util.getResolutionScope import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtExpression
@@ -43,6 +44,8 @@ class SmartCastCalculator(
receiver: KtExpression?, receiver: KtExpression?,
resolutionFacade: ResolutionFacade resolutionFacade: ResolutionFacade
) { ) {
private val dataFlowValueFactory = resolutionFacade.frontendService<DataFlowValueFactory>()
// keys are VariableDescriptor's and ThisReceiver's // keys are VariableDescriptor's and ThisReceiver's
private val entityToSmartCastInfo: Map<Any, SmartCastInfo> = processDataFlowInfo( private val entityToSmartCastInfo: Map<Any, SmartCastInfo> = processDataFlowInfo(
bindingContext.getDataFlowInfoBefore(contextElement), bindingContext.getDataFlowInfoBefore(contextElement),
@@ -82,7 +85,7 @@ class SmartCastCalculator(
val dataFlowValueToEntity: (DataFlowValue) -> Any? val dataFlowValueToEntity: (DataFlowValue) -> Any?
if (receiver != null) { if (receiver != null) {
val receiverType = bindingContext.getType(receiver) ?: return emptyMap() val receiverType = bindingContext.getType(receiver) ?: return emptyMap()
val receiverIdentifierInfo = DataFlowValueFactory.createDataFlowValue( val receiverIdentifierInfo = dataFlowValueFactory.createDataFlowValue(
receiver, receiverType, bindingContext, containingDeclarationOrModule receiver, receiverType, bindingContext, containingDeclarationOrModule
).identifierInfo ).identifierInfo
dataFlowValueToEntity = { value -> dataFlowValueToEntity = { value ->
@@ -41,6 +41,7 @@ import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.getDispatchReceiverWithSmartCast import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.getDispatchReceiverWithSmartCast
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
@@ -120,7 +121,8 @@ fun Call.resolveCandidates(
val callResolutionContext = BasicCallResolutionContext.create( val callResolutionContext = BasicCallResolutionContext.create(
bindingTrace, resolutionScope, this, expectedType, dataFlowInfo, bindingTrace, resolutionScope, this, expectedType, dataFlowInfo,
ContextDependency.INDEPENDENT, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, ContextDependency.INDEPENDENT, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
false, resolutionFacade.frontendService<LanguageVersionSettings>() false, resolutionFacade.frontendService<LanguageVersionSettings>(),
resolutionFacade.frontendService<DataFlowValueFactory>()
).replaceCollectAllCandidates(true) ).replaceCollectAllCandidates(true)
val callResolver = resolutionFacade.frontendService<CallResolver>() val callResolver = resolutionFacade.frontendService<CallResolver>()
@@ -26,8 +26,10 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.findModuleDescriptor import org.jetbrains.kotlin.idea.caches.resolve.findModuleDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.project.languageVersionSettings import org.jetbrains.kotlin.idea.project.languageVersionSettings
import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.resolve.frontendService
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelector import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelector
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
@@ -111,7 +113,8 @@ class KotlinExpressionTypeProvider : ExpressionTypeProvider<KtExpression>() {
val expressionType = element.getType(bindingContext) val expressionType = element.getType(bindingContext)
val result = expressionType?.let { typeRenderer.renderType(it) } ?: return "Type is unknown" val result = expressionType?.let { typeRenderer.renderType(it) } ?: return "Type is unknown"
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(element, expressionType, bindingContext, element.findModuleDescriptor()) val dataFlowValueFactory = element.getResolutionFacade().frontendService<DataFlowValueFactory>()
val dataFlowValue = dataFlowValueFactory.createDataFlowValue(element, expressionType, bindingContext, element.findModuleDescriptor())
val types = expressionTypeInfo.dataFlowInfo.getStableTypes(dataFlowValue, element.languageVersionSettings) val types = expressionTypeInfo.dataFlowInfo.getStableTypes(dataFlowValue, element.languageVersionSettings)
if (!types.isEmpty()) { if (!types.isEmpty()) {
return types.joinToString(separator = " & ") { typeRenderer.renderType(it) } + " (smart cast from " + result + ")" return types.joinToString(separator = " & ") { typeRenderer.renderType(it) } + " (smart cast from " + result + ")"
@@ -45,6 +45,7 @@ import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.isReallySuccess import org.jetbrains.kotlin.resolve.calls.model.isReallySuccess
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.util.DelegatingCall import org.jetbrains.kotlin.resolve.calls.util.DelegatingCall
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.resolve.scopes.LexicalScope
@@ -195,7 +196,8 @@ class UsePropertyAccessSyntaxIntention : SelfTargetingOffsetIndependentIntention
val bindingTrace = DelegatingBindingTrace(bindingContext, "Temporary trace") val bindingTrace = DelegatingBindingTrace(bindingContext, "Temporary trace")
val context = BasicCallResolutionContext.create(bindingTrace, resolutionScope, newCall, expectedType, dataFlowInfo, val context = BasicCallResolutionContext.create(bindingTrace, resolutionScope, newCall, expectedType, dataFlowInfo,
ContextDependency.INDEPENDENT, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, ContextDependency.INDEPENDENT, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
false, facade.frontendService<LanguageVersionSettings>()) false, facade.frontendService<LanguageVersionSettings>(),
facade.frontendService<DataFlowValueFactory>())
val callResolver = facade.frontendService<CallResolver>() val callResolver = facade.frontendService<CallResolver>()
val result = callResolver.resolveSimpleProperty(context) val result = callResolver.resolveSimpleProperty(context)
return result.isSuccess && result.resultingDescriptor.original == property return result.isSuccess && result.resultingDescriptor.original == property
@@ -38,7 +38,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.callUtil.getType import org.jetbrains.kotlin.resolve.calls.callUtil.getType
import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.getImplicitReceiverValue import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.getImplicitReceiverValue
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactoryImpl
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver
import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.TypeUtils
@@ -163,7 +163,7 @@ fun KtExpression.isStable(context: BindingContext = this.analyze()): Boolean {
if (this is KtConstantExpression || this is KtThisExpression) return true if (this is KtConstantExpression || this is KtThisExpression) return true
val descriptor = BindingContextUtils.extractVariableDescriptorFromReference(context, this) val descriptor = BindingContextUtils.extractVariableDescriptorFromReference(context, this)
return descriptor is VariableDescriptor && return descriptor is VariableDescriptor &&
DataFlowValueFactory.isStableValue(descriptor, DescriptorUtils.getContainingModule(descriptor)) DataFlowValueFactoryImpl.isStableValue(descriptor, DescriptorUtils.getContainingModule(descriptor))
} }
data class IfThenToSelectData( data class IfThenToSelectData(
@@ -30,7 +30,9 @@ import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.idea.KotlinBundle import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.findModuleDescriptor import org.jetbrains.kotlin.idea.caches.resolve.findModuleDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isNullExpression import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isNullExpression
import org.jetbrains.kotlin.idea.resolve.frontendService
import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
@@ -132,9 +134,12 @@ class AddExclExclCallFix(psiElement: PsiElement, val checkImplicitReceivers: Boo
} else { } else {
context[BindingContext.EXPRESSION_TYPE_INFO, psiElement]?.let { context[BindingContext.EXPRESSION_TYPE_INFO, psiElement]?.let {
val type = it.type val type = it.type
val dataFlowValueFactory = psiElement.getResolutionFacade().frontendService<DataFlowValueFactory>()
if (type != null) { if (type != null) {
val nullability = it.dataFlowInfo.getStableNullability( val nullability = it.dataFlowInfo.getStableNullability(
DataFlowValueFactory.createDataFlowValue(psiElement, type, context, psiElement.findModuleDescriptor()) dataFlowValueFactory.createDataFlowValue(psiElement, type, context, psiElement.findModuleDescriptor())
) )
if (!nullability.canBeNonNull()) return null if (!nullability.canBeNonNull()) return null
} }
@@ -20,9 +20,11 @@ import com.intellij.refactoring.psi.SearchUtils
import org.jetbrains.kotlin.builtins.isFunctionType import org.jetbrains.kotlin.builtins.isFunctionType
import org.jetbrains.kotlin.cfg.pseudocode.* import org.jetbrains.kotlin.cfg.pseudocode.*
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.project.builtIns import org.jetbrains.kotlin.idea.project.builtIns
import org.jetbrains.kotlin.idea.project.languageVersionSettings import org.jetbrains.kotlin.idea.project.languageVersionSettings
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
import org.jetbrains.kotlin.idea.resolve.frontendService
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
@@ -150,8 +152,10 @@ fun KtExpression.guessTypes(
val theType1 = context.getType(this) val theType1 = context.getType(this)
if (theType1 != null && isAcceptable(theType1)) { if (theType1 != null && isAcceptable(theType1)) {
val dataFlowInfo = context.getDataFlowInfoAfter(this) val dataFlowInfo = context.getDataFlowInfoAfter(this)
val possibleTypes = dataFlowInfo.getCollectedTypes(DataFlowValueFactory.createDataFlowValue(this, theType1, context, module), val dataFlowValueFactory = this.getResolutionFacade().frontendService<DataFlowValueFactory>()
languageVersionSettings) val dataFlowValue = dataFlowValueFactory.createDataFlowValue(this, theType1, context, module)
val possibleTypes = dataFlowInfo.getCollectedTypes(dataFlowValue, languageVersionSettings)
return if (possibleTypes.isNotEmpty()) possibleTypes.toTypedArray() else arrayOf(theType1) return if (possibleTypes.isNotEmpty()) possibleTypes.toTypedArray() else arrayOf(theType1)
} }
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.idea.project.languageVersionSettings
import org.jetbrains.kotlin.idea.refactoring.introduce.ExtractableSubstringInfo import org.jetbrains.kotlin.idea.refactoring.introduce.ExtractableSubstringInfo
import org.jetbrains.kotlin.idea.refactoring.introduce.extractableSubstringInfo import org.jetbrains.kotlin.idea.refactoring.introduce.extractableSubstringInfo
import org.jetbrains.kotlin.idea.refactoring.introduce.substringContextOrThis import org.jetbrains.kotlin.idea.refactoring.introduce.substringContextOrThis
import org.jetbrains.kotlin.idea.resolve.frontendService
import org.jetbrains.kotlin.idea.util.getResolutionScope import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.idea.util.psi.patternMatching.KotlinPsiRange import org.jetbrains.kotlin.idea.util.psi.patternMatching.KotlinPsiRange
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
@@ -182,15 +183,16 @@ data class ExtractionData(
} }
fun getPossibleTypes(expression: KtExpression, resolvedCall: ResolvedCall<*>?, context: BindingContext): Set<KotlinType> { fun getPossibleTypes(expression: KtExpression, resolvedCall: ResolvedCall<*>?, context: BindingContext): Set<KotlinType> {
val dataFlowValueFactory = expression.getResolutionFacade().frontendService<DataFlowValueFactory>()
val dataFlowInfo = context.getDataFlowInfoAfter(expression) val dataFlowInfo = context.getDataFlowInfoAfter(expression)
resolvedCall?.getImplicitReceiverValue()?.let { resolvedCall?.getImplicitReceiverValue()?.let {
return dataFlowInfo.getCollectedTypes(DataFlowValueFactory.createDataFlowValueForStableReceiver(it), expression.languageVersionSettings) return dataFlowInfo.getCollectedTypes(dataFlowValueFactory.createDataFlowValueForStableReceiver(it), expression.languageVersionSettings)
} }
val type = resolvedCall?.resultingDescriptor?.returnType ?: return emptySet() val type = resolvedCall?.resultingDescriptor?.returnType ?: return emptySet()
val containingDescriptor = expression.getResolutionScope(context, expression.getResolutionFacade()).ownerDescriptor val containingDescriptor = expression.getResolutionScope(context, expression.getResolutionFacade()).ownerDescriptor
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, type, context, containingDescriptor) val dataFlowValue = dataFlowValueFactory.createDataFlowValue(expression, type, context, containingDescriptor)
return dataFlowInfo.getCollectedTypes(dataFlowValue, expression.languageVersionSettings) return dataFlowInfo.getCollectedTypes(dataFlowValue, expression.languageVersionSettings)
} }
@@ -27,10 +27,12 @@ import org.jetbrains.kotlin.cfg.pseudocode.getExpectedTypePredicate
import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.InstructionWithReceivers import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.InstructionWithReceivers
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
import org.jetbrains.kotlin.idea.core.NewDeclarationNameValidator import org.jetbrains.kotlin.idea.core.NewDeclarationNameValidator
import org.jetbrains.kotlin.idea.project.languageVersionSettings import org.jetbrains.kotlin.idea.project.languageVersionSettings
import org.jetbrains.kotlin.idea.resolve.frontendService
import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.lexer.KtToken import org.jetbrains.kotlin.lexer.KtToken
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
@@ -328,9 +330,11 @@ private fun suggestParameterType(
val typeByDataFlowInfo = if (useSmartCastsIfPossible) { val typeByDataFlowInfo = if (useSmartCastsIfPossible) {
val callElement = resolvedCall!!.call.callElement val callElement = resolvedCall!!.call.callElement
val dataFlowInfo = bindingContext.getDataFlowInfoAfter(callElement) val dataFlowInfo = bindingContext.getDataFlowInfoAfter(callElement)
val dataFlowValueFactory = callElement.getResolutionFacade().frontendService<DataFlowValueFactory>()
val possibleTypes = dataFlowInfo.getCollectedTypes( val possibleTypes = dataFlowInfo.getCollectedTypes(
DataFlowValueFactory.createDataFlowValueForStableReceiver(receiverToExtract), dataFlowValueFactory.createDataFlowValueForStableReceiver(receiverToExtract),
callElement.languageVersionSettings callElement.languageVersionSettings
) )
if (possibleTypes.isNotEmpty()) CommonSupertypes.commonSupertype(possibleTypes) else null if (possibleTypes.isNotEmpty()) CommonSupertypes.commonSupertype(possibleTypes) else null
} else null } else null
@@ -30,14 +30,13 @@ import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoAfter
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.smartcasts.IdentifierInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.IdentifierInfo
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver
abstract class AbstractDataFlowValueRenderingTest: KotlinLightCodeInsightFixtureTestCase() { abstract class AbstractDataFlowValueRenderingTest: KotlinLightCodeInsightFixtureTestCase() {
private fun IdentifierInfo.render(): String? = when (this) { private fun IdentifierInfo.render(): String? = when (this) {
is DataFlowValueFactory.ExpressionIdentifierInfo -> expression.text is IdentifierInfo.Expression -> expression.text
is IdentifierInfo.Receiver -> (value as? ImplicitReceiver)?.declarationDescriptor?.name?.let { "this@$it" } is IdentifierInfo.Receiver -> (value as? ImplicitReceiver)?.declarationDescriptor?.name?.let { "this@$it" }
is IdentifierInfo.Variable -> variable.name.asString() is IdentifierInfo.Variable -> variable.name.asString()
is IdentifierInfo.PackageOrClass -> (descriptor as? PackageViewDescriptor)?.let { it.fqName.asString() } is IdentifierInfo.PackageOrClass -> (descriptor as? PackageViewDescriptor)?.let { it.fqName.asString() }
@@ -38,6 +38,7 @@ import org.jetbrains.kotlin.psi.psiUtil.getTextWithLocation
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactoryImpl
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant
import org.jetbrains.kotlin.resolve.constants.EnumValue import org.jetbrains.kotlin.resolve.constants.EnumValue
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
@@ -52,6 +53,7 @@ private constructor(private val whenExpression: KtWhenExpression, context: Trans
private val type: KotlinType? private val type: KotlinType?
private val uniqueConstants = mutableSetOf<Any>() private val uniqueConstants = mutableSetOf<Any>()
private val uniqueEnumNames = mutableSetOf<String>() private val uniqueEnumNames = mutableSetOf<String>()
private val dataFlowValueFactory: DataFlowValueFactory = DataFlowValueFactoryImpl()
private val isExhaustive: Boolean private val isExhaustive: Boolean
get() { get() {
@@ -124,7 +126,7 @@ private constructor(private val whenExpression: KtWhenExpression, context: Trans
val ktSubject = whenExpression.subjectExpression ?: return null val ktSubject = whenExpression.subjectExpression ?: return null
val subjectType = bindingContext().getType(ktSubject) ?: return null val subjectType = bindingContext().getType(ktSubject) ?: return null
val dataFlow = DataFlowValueFactory.createDataFlowValue( val dataFlow = dataFlowValueFactory.createDataFlowValue(
ktSubject, subjectType, bindingContext(), context().declarationDescriptor ?: context().currentModule) ktSubject, subjectType, bindingContext(), context().declarationDescriptor ?: context().currentModule)
val languageVersionSettings = context().config.configuration.languageVersionSettings val languageVersionSettings = context().config.configuration.languageVersionSettings
val expectedTypes = bindingContext().getDataFlowInfoBefore(ktSubject).getStableTypes(dataFlow, languageVersionSettings) + val expectedTypes = bindingContext().getDataFlowInfoBefore(ktSubject).getStableTypes(dataFlow, languageVersionSettings) +
@@ -35,7 +35,7 @@ import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactoryImpl
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.expressions.OperatorConventions import org.jetbrains.kotlin.types.expressions.OperatorConventions
@@ -112,7 +112,7 @@ object EqualsBOIF : BinaryOperationIntrinsicFactory {
val descriptor = context.declarationDescriptor ?: context.currentModule val descriptor = context.declarationDescriptor ?: context.currentModule
val ktType = bindingContext.getType(expression) ?: return null val ktType = bindingContext.getType(expression) ?: return null
val dataFlow = DataFlowValueFactory.createDataFlowValue(expression, ktType, bindingContext, descriptor) val dataFlow = DataFlowValueFactoryImpl().createDataFlowValue(expression, ktType, bindingContext, descriptor)
val isPrimitiveFn = KotlinBuiltIns::isPrimitiveTypeOrNullablePrimitiveType val isPrimitiveFn = KotlinBuiltIns::isPrimitiveTypeOrNullablePrimitiveType
val languageVersionSettings = context.config.configuration.languageVersionSettings val languageVersionSettings = context.config.configuration.languageVersionSettings