diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContextUtils.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContextUtils.kt index 850931efc32..25642ff63ca 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContextUtils.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BindingContextUtils.kt @@ -79,7 +79,12 @@ public fun BindingTrace.recordScope(scope: LexicalScope, element: KtElement?) { public fun BindingContext.getDataFlowInfo(position: PsiElement): DataFlowInfo { for (element in position.parentsWithSelf) { - (element as? KtExpression)?.let { this[BindingContext.EXPRESSION_TYPE_INFO, it] }?.let { return it.dataFlowInfo } + (element as? KtExpression)?.let { + val parent = it.parent + //TODO: it's a hack because KotlinTypeInfo with wrong DataFlowInfo stored for call expression after qualifier + if (parent is KtQualifiedExpression && it == parent.selectorExpression) return@let null + this[BindingContext.EXPRESSION_TYPE_INFO, it] + }?.let { return it.dataFlowInfo } } return DataFlowInfo.EMPTY } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/typeUtils.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/typeUtils.kt index 1e9ec2891fa..f608615f4b4 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/typeUtils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/typeUtils.kt @@ -31,11 +31,11 @@ import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getAssignmentByLHS import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsStatement import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory import org.jetbrains.kotlin.resolve.descriptorUtil.resolveTopLevelClass import org.jetbrains.kotlin.resolve.scopes.HierarchicalScope -import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.checker.KotlinTypeChecker @@ -127,9 +127,9 @@ fun KtExpression.guessTypes( // if we know the actual type of the expression val theType1 = context.getType(this) if (theType1 != null) { - val dataFlowInfo = context[BindingContext.EXPRESSION_TYPE_INFO, this]?.dataFlowInfo - val possibleTypes = dataFlowInfo?.getPossibleTypes(DataFlowValueFactory.createDataFlowValue(this, theType1, context, module)) - return if (possibleTypes != null && possibleTypes.isNotEmpty()) possibleTypes.toTypedArray() else arrayOf(theType1) + val dataFlowInfo = context.getDataFlowInfo(this) + val possibleTypes = dataFlowInfo.getPossibleTypes(DataFlowValueFactory.createDataFlowValue(this, theType1, context, module)) + return if (possibleTypes.isNotEmpty()) possibleTypes.toTypedArray() else arrayOf(theType1) } // expression has an expected type diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/ExtractionData.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/ExtractionData.kt index 69ca04098d4..84fcc1a871b 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/ExtractionData.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/ExtractionData.kt @@ -37,6 +37,7 @@ import org.jetbrains.kotlin.psi.psiUtil.isInsideOf import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall @@ -175,16 +176,16 @@ data class ExtractionData( } fun getPossibleTypes(expression: KtExpression, resolvedCall: ResolvedCall<*>?, context: BindingContext): Set { - val typeInfo = context[BindingContext.EXPRESSION_TYPE_INFO, expression] ?: return emptySet() + val dataFlowInfo = context.getDataFlowInfo(expression) (resolvedCall?.getImplicitReceiverValue() as? ImplicitReceiver)?.let { - return typeInfo.dataFlowInfo.getPossibleTypes(DataFlowValueFactory.createDataFlowValueForStableReceiver(it)) + return dataFlowInfo.getPossibleTypes(DataFlowValueFactory.createDataFlowValueForStableReceiver(it)) } val type = resolvedCall?.resultingDescriptor?.returnType ?: return emptySet() val containingDescriptor = expression.getResolutionScope(context, expression.getResolutionFacade()).ownerDescriptor val dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, type, context, containingDescriptor) - return typeInfo.dataFlowInfo.getPossibleTypes(dataFlowValue) + return dataFlowInfo.getPossibleTypes(dataFlowValue) } fun getBrokenReferencesInfo(body: KtBlockExpression): List { diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/inferParameterInfo.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/inferParameterInfo.kt index 5bdf9018ca0..9da5ae62fb5 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/inferParameterInfo.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/introduce/extractionEngine/inferParameterInfo.kt @@ -34,6 +34,7 @@ import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis import org.jetbrains.kotlin.psi.psiUtil.isInsideOf import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory import org.jetbrains.kotlin.resolve.calls.tasks.isSynthesizedInvoke @@ -270,6 +271,7 @@ private fun suggestParameterType( originalDescriptor.valueParameters.map { it.type }, originalDescriptor.returnType ?: builtIns.defaultReturnType) } + parameterExpression != null -> (if (useSmartCastsIfPossible) bindingContext[BindingContext.SMARTCAST, parameterExpression] else null) ?: bindingContext.getType(parameterExpression) @@ -277,17 +279,19 @@ private fun suggestParameterType( (bindingContext[BindingContext.REFERENCE_TARGET, it] as? CallableDescriptor)?.returnType } ?: if (receiverToExtract.exists()) receiverToExtract.type else null + receiverToExtract is ImplicitReceiver -> { val calleeExpression = resolvedCall!!.call.calleeExpression val typeByDataFlowInfo = if (useSmartCastsIfPossible) { - bindingContext[BindingContext.EXPRESSION_TYPE_INFO, calleeExpression]?.dataFlowInfo?.let { dataFlowInfo -> - val possibleTypes = dataFlowInfo.getPossibleTypes(DataFlowValueFactory.createDataFlowValueForStableReceiver(receiverToExtract)) - if (possibleTypes.isNotEmpty()) CommonSupertypes.commonSupertype(possibleTypes) else null - } + val dataFlowInfo = bindingContext.getDataFlowInfo(resolvedCall!!.call.callElement) + val possibleTypes = dataFlowInfo.getPossibleTypes(DataFlowValueFactory.createDataFlowValueForStableReceiver(receiverToExtract)) + if (possibleTypes.isNotEmpty()) CommonSupertypes.commonSupertype(possibleTypes) else null } else null typeByDataFlowInfo ?: receiverToExtract.type } + receiverToExtract.exists() -> receiverToExtract.type + else -> null } ?: builtIns.defaultParameterType } diff --git a/idea/testData/parameterInfo/functionCall/SmartCastReceiver.kt b/idea/testData/parameterInfo/functionCall/SmartCastReceiver.kt new file mode 100644 index 00000000000..bb898df9d47 --- /dev/null +++ b/idea/testData/parameterInfo/functionCall/SmartCastReceiver.kt @@ -0,0 +1,11 @@ +interface I + +fun I.foo(p: Int): Boolean = true + +fun foo(o: Any) { + if (o is I) { + o.foo() + } +} + +//Text: (p: Int), Disabled: false, Strikeout: false, Green: true \ No newline at end of file diff --git a/idea/testData/parameterInfo/functionCall/SmartCastReceiver2.kt b/idea/testData/parameterInfo/functionCall/SmartCastReceiver2.kt new file mode 100644 index 00000000000..d6830004309 --- /dev/null +++ b/idea/testData/parameterInfo/functionCall/SmartCastReceiver2.kt @@ -0,0 +1,11 @@ +interface I + +fun I.foo(p: Int): Boolean = true + +fun foo(o: Any?) { + if (o is I?) { + o?.foo() + } +} + +//Text: (p: Int), Disabled: false, Strikeout: false, Green: true \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/parameterInfo/ParameterInfoTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/parameterInfo/ParameterInfoTestGenerated.java index 0670db544ad..ac587e516af 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/parameterInfo/ParameterInfoTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/parameterInfo/ParameterInfoTestGenerated.java @@ -214,6 +214,18 @@ public class ParameterInfoTestGenerated extends AbstractParameterInfoTest { doTest(fileName); } + @TestMetadata("SmartCastReceiver.kt") + public void testSmartCastReceiver() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/parameterInfo/functionCall/SmartCastReceiver.kt"); + doTest(fileName); + } + + @TestMetadata("SmartCastReceiver2.kt") + public void testSmartCastReceiver2() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/parameterInfo/functionCall/SmartCastReceiver2.kt"); + doTest(fileName); + } + @TestMetadata("SubstituteExpectedType.kt") public void testSubstituteExpectedType() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/parameterInfo/functionCall/SubstituteExpectedType.kt");