Remove dependencies on data flow aware expression type in BindingContext
`BindingContext.getType`'s behaviour on argument expression has been different for OI and NI for some time. New inference used to rewrite argument's type after smartcast, which led to missing subsequent smartcasts in some cases. This commit makes retrieval of smartcasted argument type explicit.
This commit is contained in:
@@ -28,7 +28,7 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.core.CollectingNameValidator
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.getDataFlowAwareTypes
|
||||
import org.jetbrains.kotlin.idea.quickfix.quickfixUtil.getDataFlowAwareTypes
|
||||
import org.jetbrains.kotlin.idea.refactoring.changeSignature.*
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
||||
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
|
||||
import org.jetbrains.kotlin.idea.core.mapArgumentsToParameters
|
||||
import org.jetbrains.kotlin.idea.quickfix.quickfixUtil.getDataFlowAwareTypes
|
||||
import org.jetbrains.kotlin.idea.refactoring.canRefactor
|
||||
import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinChangeSignatureConfiguration
|
||||
import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinMethodDescriptor
|
||||
@@ -102,8 +103,10 @@ abstract class ChangeFunctionSignatureFix(
|
||||
val call = originalElement.getCall(bindingContext) ?: return null
|
||||
val argumentToParameter = call.mapArgumentsToParameters(functionDescriptor)
|
||||
val hasTypeMismatches = argumentToParameter.any { (argument, parameter) ->
|
||||
val argumentType = argument.getArgumentExpression()?.let { bindingContext.getType(it) }
|
||||
argumentType == null || !KotlinTypeChecker.DEFAULT.isSubtypeOf(argumentType, parameter.type)
|
||||
val argumentTypes = argument.getArgumentExpression()?.let { getDataFlowAwareTypes(it, bindingContext) }
|
||||
argumentTypes?.none { dataFlowAwareType ->
|
||||
KotlinTypeChecker.DEFAULT.isSubtypeOf(dataFlowAwareType, parameter.type)
|
||||
} ?: true
|
||||
}
|
||||
return AddFunctionParametersFix(originalElement, functionDescriptor, hasTypeMismatches)
|
||||
}
|
||||
|
||||
+1
-22
@@ -9,12 +9,9 @@ import com.intellij.refactoring.psi.SearchUtils
|
||||
import org.jetbrains.kotlin.builtins.isFunctionType
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.*
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.project.builtIns
|
||||
import org.jetbrains.kotlin.idea.project.languageVersionSettings
|
||||
import org.jetbrains.kotlin.idea.quickfix.quickfixUtil.getDataFlowAwareTypes
|
||||
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.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
@@ -24,9 +21,7 @@ import org.jetbrains.kotlin.psi.psiUtil.getAssignmentByLHS
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoAfter
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsStatement
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||
import org.jetbrains.kotlin.resolve.constants.IntegerLiteralTypeConstructor
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.resolveTopLevelClass
|
||||
import org.jetbrains.kotlin.resolve.scopes.HierarchicalScope
|
||||
@@ -35,7 +30,6 @@ import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||
import org.jetbrains.kotlin.types.typeUtil.supertypes
|
||||
import org.jetbrains.kotlin.utils.ifEmpty
|
||||
import java.util.*
|
||||
|
||||
internal operator fun KotlinType.contains(inner: KotlinType): Boolean {
|
||||
@@ -335,18 +329,3 @@ private fun TypePredicate.getRepresentativeTypes(): Set<KotlinType> {
|
||||
else -> throw AssertionError("Invalid type predicate: $this")
|
||||
}
|
||||
}
|
||||
|
||||
fun getDataFlowAwareTypes(
|
||||
expression: KtExpression,
|
||||
bindingContext: BindingContext = expression.analyze(),
|
||||
originalType: KotlinType? = bindingContext.getType(expression)
|
||||
): Collection<KotlinType> {
|
||||
if (originalType == null) return emptyList()
|
||||
val dataFlowInfo = bindingContext.getDataFlowInfoAfter(expression)
|
||||
val dataFlowValueFactory = expression.getResolutionFacade().frontendService<DataFlowValueFactory>()
|
||||
val expressionType = bindingContext.getType(expression) ?: return listOf(originalType)
|
||||
val dataFlowValue = dataFlowValueFactory.createDataFlowValue(
|
||||
expression, expressionType, bindingContext, expression.getResolutionFacade().moduleDescriptor
|
||||
)
|
||||
return dataFlowInfo.getCollectedTypes(dataFlowValue, expression.languageVersionSettings).ifEmpty { listOf(originalType) }
|
||||
}
|
||||
+6
-1
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.analyzeAndGetResult
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
|
||||
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
|
||||
import org.jetbrains.kotlin.idea.quickfix.quickfixUtil.getDataFlowAwareTypes
|
||||
import org.jetbrains.kotlin.idea.refactoring.canRefactor
|
||||
import org.jetbrains.kotlin.idea.refactoring.getExtractionContainers
|
||||
import org.jetbrains.kotlin.idea.refactoring.isInterfaceClass
|
||||
@@ -119,7 +120,11 @@ sealed class CreateCallableFromCallActionFactory<E : KtExpression>(
|
||||
is ReceiverValue -> {
|
||||
val originalType = receiver.type
|
||||
val finalType = if (receiver is ExpressionReceiver) {
|
||||
getDataFlowAwareTypes(receiver.expression, context, originalType).firstOrNull() ?: originalType
|
||||
getDataFlowAwareTypes(
|
||||
receiver.expression,
|
||||
context,
|
||||
originalType
|
||||
).firstOrNull() ?: originalType
|
||||
} else originalType
|
||||
TypeInfo(finalType, Variance.IN_VARIANCE)
|
||||
}
|
||||
|
||||
@@ -19,11 +19,21 @@ package org.jetbrains.kotlin.idea.quickfix.quickfixUtil
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.project.languageVersionSettings
|
||||
import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction
|
||||
import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactory
|
||||
import org.jetbrains.kotlin.idea.resolve.frontendService
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtPrimaryConstructor
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoAfter
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.utils.ifEmpty
|
||||
|
||||
inline fun <reified T : PsiElement> Diagnostic.createIntentionForFirstParentOfType(
|
||||
factory: (T) -> KotlinQuickFixAction<T>?
|
||||
@@ -40,3 +50,18 @@ fun KtPrimaryConstructor.addConstructorKeyword(): PsiElement? {
|
||||
val keyword = KtPsiFactory(this).createConstructorKeyword()
|
||||
return addAfter(keyword, modifierList ?: return null)
|
||||
}
|
||||
|
||||
fun getDataFlowAwareTypes(
|
||||
expression: KtExpression,
|
||||
bindingContext: BindingContext = expression.analyze(),
|
||||
originalType: KotlinType? = bindingContext.getType(expression)
|
||||
): Collection<KotlinType> {
|
||||
if (originalType == null) return emptyList()
|
||||
val dataFlowInfo = bindingContext.getDataFlowInfoAfter(expression)
|
||||
val dataFlowValueFactory = expression.getResolutionFacade().frontendService<DataFlowValueFactory>()
|
||||
val expressionType = bindingContext.getType(expression) ?: return listOf(originalType)
|
||||
val dataFlowValue = dataFlowValueFactory.createDataFlowValue(
|
||||
expression, expressionType, bindingContext, expression.getResolutionFacade().moduleDescriptor
|
||||
)
|
||||
return dataFlowInfo.getCollectedTypes(dataFlowValue, expression.languageVersionSettings).ifEmpty { listOf(originalType) }
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||
import org.jetbrains.kotlin.idea.quickfix.quickfixUtil.getDataFlowAwareTypes
|
||||
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
|
||||
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
|
||||
import org.jetbrains.kotlin.idea.test.configureCompilerOptions
|
||||
@@ -148,7 +149,9 @@ abstract class AbstractPartialBodyResolveTest : KotlinLightCodeInsightFixtureTes
|
||||
} else {
|
||||
expression
|
||||
}
|
||||
val type = bindingContext.getType(expressionWithType)
|
||||
|
||||
val nonDataFlowAwareType = bindingContext.getType(expressionWithType)
|
||||
val type = getDataFlowAwareTypes(expressionWithType, bindingContext, nonDataFlowAwareType).singleOrNull() ?: nonDataFlowAwareType
|
||||
|
||||
return ResolveData(target, type, processedStatements)
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
internal class C {
|
||||
fun foo(s: String?): String? {
|
||||
fun foo(s: String?): String {
|
||||
return s ?: ""
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user