KT-10006 Parameter Info does not work for smart cast receiver
#KT-10006 Fixed
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
+4
-4
@@ -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
|
||||
|
||||
+4
-3
@@ -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<KotlinType> {
|
||||
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<ResolvedReferenceInfo> {
|
||||
|
||||
+8
-4
@@ -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
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
interface I
|
||||
|
||||
fun I.foo(p: Int): Boolean = true
|
||||
|
||||
fun foo(o: Any) {
|
||||
if (o is I) {
|
||||
o.foo(<caret>)
|
||||
}
|
||||
}
|
||||
|
||||
//Text: (<highlight>p: Int</highlight>), Disabled: false, Strikeout: false, Green: true
|
||||
@@ -0,0 +1,11 @@
|
||||
interface I
|
||||
|
||||
fun I.foo(p: Int): Boolean = true
|
||||
|
||||
fun foo(o: Any?) {
|
||||
if (o is I?) {
|
||||
o?.foo(<caret>)
|
||||
}
|
||||
}
|
||||
|
||||
//Text: (<highlight>p: Int</highlight>), Disabled: false, Strikeout: false, Green: true
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user