Create from Usage: Support smart casts on explicit receivers

#KT-24069 Fixed
This commit is contained in:
Alexey Sedunov
2018-05-10 19:16:58 +03:00
parent a92a4a2a6d
commit a5a13b74f5
5 changed files with 43 additions and 4 deletions
@@ -164,7 +164,7 @@ fun KtExpression.guessTypes(
// if we know the actual type of the expression
val theType1 = context.getType(this)
if (theType1 != null && isAcceptable(theType1)) {
return getDataFlowAwareTypes(this, context).toTypedArray()
return getDataFlowAwareTypes(this, context, theType1).toTypedArray()
}
}
@@ -341,8 +341,12 @@ private fun TypePredicate.getRepresentativeTypes(): Set<KotlinType> {
}
}
fun getDataFlowAwareTypes(expression: KtExpression, bindingContext: BindingContext = expression.analyze()): List<KotlinType> {
val originalType = bindingContext.getType(expression) ?: return emptyList()
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 dataFlowValue = dataFlowValueFactory.createDataFlowValue(
@@ -129,7 +129,13 @@ sealed class CreateCallableFromCallActionFactory<E : KtExpression>(
if (javaClass == null || !javaClass.canRefactor()) return null
TypeInfo.StaticContextRequired(TypeInfo(javaClassifier.defaultType, Variance.IN_VARIANCE))
}
is ReceiverValue -> TypeInfo(receiver.type, Variance.IN_VARIANCE)
is ReceiverValue -> {
val originalType = receiver.type
val finalType = if (receiver is ExpressionReceiver) {
getDataFlowAwareTypes(receiver.expression, context, originalType).firstOrNull() ?: originalType
} else originalType
TypeInfo(finalType, Variance.IN_VARIANCE)
}
else -> throw AssertionError("Unexpected receiver: $receiver")
}
}
@@ -0,0 +1,10 @@
// "Create member function 'SomeObj.doSomething'" "true"
class SomeObj { }
fun doSomething(p: Any): List<Number>{
if (p is SomeObj){
p.<caret>doSomething()
}
return emptyList()
}
@@ -0,0 +1,14 @@
// "Create member function 'SomeObj.doSomething'" "true"
class SomeObj {
fun doSomething() {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
}
fun doSomething(p: Any): List<Number>{
if (p is SomeObj){
p.doSomething()
}
return emptyList()
}
@@ -3114,6 +3114,11 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
runTest("idea/testData/quickfix/createFromUsage/createFunction/call/qualifiedCallInStringTemplateRuntime.kt");
}
@TestMetadata("receiverWithSmartCast.kt")
public void testReceiverWithSmartCast() throws Exception {
runTest("idea/testData/quickfix/createFromUsage/createFunction/call/receiverWithSmartCast.kt");
}
@TestMetadata("refInImport.kt")
public void testRefInImport() throws Exception {
runTest("idea/testData/quickfix/createFromUsage/createFunction/call/refInImport.kt");