Extraction Engine: Respect smart casts applied to "this" references
#KT-7447
This commit is contained in:
+21
-5
@@ -69,8 +69,10 @@ import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
|||||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsStatement
|
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsStatement
|
||||||
import org.jetbrains.kotlin.resolve.calls.CallTransformer
|
import org.jetbrains.kotlin.resolve.calls.CallTransformer
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||||
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
||||||
import org.jetbrains.kotlin.resolve.scopes.JetScopeUtils
|
import org.jetbrains.kotlin.resolve.scopes.JetScopeUtils
|
||||||
|
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.resolve.scopes.receivers.ThisReceiver
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver
|
||||||
import org.jetbrains.kotlin.types.*
|
import org.jetbrains.kotlin.types.*
|
||||||
@@ -642,13 +644,27 @@ private fun ExtractionData.inferParametersInfo(
|
|||||||
|
|
||||||
val extractParameter = extractThis || extractLocalVar
|
val extractParameter = extractThis || extractLocalVar
|
||||||
if (extractParameter) {
|
if (extractParameter) {
|
||||||
val parameterType = when {
|
val parameterExpression = when {
|
||||||
receiverToExtract.exists() -> receiverToExtract.getType()
|
receiverToExtract is ExpressionReceiver -> receiverToExtract.getExpression()
|
||||||
else -> bindingContext[BindingContext.SMARTCAST, originalRef]
|
receiverToExtract.exists() -> null
|
||||||
?: bindingContext[BindingContext.EXPRESSION_TYPE, originalRef]
|
else -> (originalRef.getParent() as? JetThisExpression) ?: originalRef
|
||||||
?: DEFAULT_PARAMETER_TYPE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val parameterType = when {
|
||||||
|
parameterExpression != null -> bindingContext[BindingContext.SMARTCAST, parameterExpression]
|
||||||
|
?: bindingContext[BindingContext.EXPRESSION_TYPE, parameterExpression]
|
||||||
|
?: if (receiverToExtract.exists()) receiverToExtract.getType() else null
|
||||||
|
receiverToExtract is ThisReceiver -> {
|
||||||
|
val calleeExpression = resolvedCall!!.getCall().getCalleeExpression()
|
||||||
|
bindingContext[BindingContext.EXPRESSION_DATA_FLOW_INFO, calleeExpression]?.let { dataFlowInfo ->
|
||||||
|
val possibleTypes = dataFlowInfo.getPossibleTypes(DataFlowValueFactory.createDataFlowValue(receiverToExtract))
|
||||||
|
CommonSupertypes.commonSupertype(possibleTypes)
|
||||||
|
} ?: receiverToExtract.getType()
|
||||||
|
}
|
||||||
|
receiverToExtract.exists() -> receiverToExtract.getType()
|
||||||
|
else -> null
|
||||||
|
} ?: DEFAULT_PARAMETER_TYPE
|
||||||
|
|
||||||
val parameter = extractedDescriptorToParameter.getOrPut(descriptorToExtract) {
|
val parameter = extractedDescriptorToParameter.getOrPut(descriptorToExtract) {
|
||||||
val argumentText =
|
val argumentText =
|
||||||
if (hasThisReceiver && extractThis) {
|
if (hasThisReceiver && extractThis) {
|
||||||
|
|||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
// SUGGESTED_NAMES: i, getB
|
||||||
|
// PARAM_DESCRIPTOR: internal fun A.ext(): kotlin.Unit defined in root package
|
||||||
|
// PARAM_TYPES: B
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
val a: A = B()
|
||||||
|
a.ext()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun A.ext() {
|
||||||
|
if (this !is B) return
|
||||||
|
val b = <selection>this.foo()</selection>
|
||||||
|
}
|
||||||
|
|
||||||
|
open class A
|
||||||
|
class B: A() {
|
||||||
|
fun foo() = 1
|
||||||
|
}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
// SUGGESTED_NAMES: i, getB
|
||||||
|
// PARAM_DESCRIPTOR: internal fun A.ext(): kotlin.Unit defined in root package
|
||||||
|
// PARAM_TYPES: B
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
val a: A = B()
|
||||||
|
a.ext()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun A.ext() {
|
||||||
|
if (this !is B) return
|
||||||
|
val b = i()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun B.i() = this.foo()
|
||||||
|
|
||||||
|
open class A
|
||||||
|
class B: A() {
|
||||||
|
fun foo() = 1
|
||||||
|
}
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
// SUGGESTED_NAMES: i, getB
|
||||||
|
// PARAM_DESCRIPTOR: internal fun A.ext(): kotlin.Unit defined in root package
|
||||||
|
// PARAM_TYPES: B
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
val a: A = B()
|
||||||
|
a.ext()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun A.ext() {
|
||||||
|
if (this !is B) return
|
||||||
|
val b = <selection>foo()</selection>
|
||||||
|
}
|
||||||
|
|
||||||
|
open class A
|
||||||
|
class B: A() {
|
||||||
|
fun foo() = 1
|
||||||
|
}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
// SUGGESTED_NAMES: i, getB
|
||||||
|
// PARAM_DESCRIPTOR: internal fun A.ext(): kotlin.Unit defined in root package
|
||||||
|
// PARAM_TYPES: B
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
val a: A = B()
|
||||||
|
a.ext()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun A.ext() {
|
||||||
|
if (this !is B) return
|
||||||
|
val b = i()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun B.i() = foo()
|
||||||
|
|
||||||
|
open class A
|
||||||
|
class B: A() {
|
||||||
|
fun foo() = 1
|
||||||
|
}
|
||||||
+12
@@ -1643,6 +1643,12 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
|||||||
doExtractFunctionTest(fileName);
|
doExtractFunctionTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("explicitThisWithSmartCast.kt")
|
||||||
|
public void testExplicitThisWithSmartCast() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/parameters/extractThis/explicitThisWithSmartCast.kt");
|
||||||
|
doExtractFunctionTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("implicitAndExplicitLabeledThisInMember.kt")
|
@TestMetadata("implicitAndExplicitLabeledThisInMember.kt")
|
||||||
public void testImplicitAndExplicitLabeledThisInMember() throws Exception {
|
public void testImplicitAndExplicitLabeledThisInMember() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/parameters/extractThis/implicitAndExplicitLabeledThisInMember.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/parameters/extractThis/implicitAndExplicitLabeledThisInMember.kt");
|
||||||
@@ -1667,6 +1673,12 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
|||||||
doExtractFunctionTest(fileName);
|
doExtractFunctionTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("implicitThisWithSmartCast.kt")
|
||||||
|
public void testImplicitThisWithSmartCast() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/parameters/extractThis/implicitThisWithSmartCast.kt");
|
||||||
|
doExtractFunctionTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("qualifiedThisAsArgument.kt")
|
@TestMetadata("qualifiedThisAsArgument.kt")
|
||||||
public void testQualifiedThisAsArgument() throws Exception {
|
public void testQualifiedThisAsArgument() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/parameters/extractThis/qualifiedThisAsArgument.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/parameters/extractThis/qualifiedThisAsArgument.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user