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.calls.CallTransformer
|
||||
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.JetScopeUtils
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver
|
||||
import org.jetbrains.kotlin.types.*
|
||||
@@ -642,13 +644,27 @@ private fun ExtractionData.inferParametersInfo(
|
||||
|
||||
val extractParameter = extractThis || extractLocalVar
|
||||
if (extractParameter) {
|
||||
val parameterType = when {
|
||||
receiverToExtract.exists() -> receiverToExtract.getType()
|
||||
else -> bindingContext[BindingContext.SMARTCAST, originalRef]
|
||||
?: bindingContext[BindingContext.EXPRESSION_TYPE, originalRef]
|
||||
?: DEFAULT_PARAMETER_TYPE
|
||||
val parameterExpression = when {
|
||||
receiverToExtract is ExpressionReceiver -> receiverToExtract.getExpression()
|
||||
receiverToExtract.exists() -> null
|
||||
else -> (originalRef.getParent() as? JetThisExpression) ?: originalRef
|
||||
}
|
||||
|
||||
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 argumentText =
|
||||
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);
|
||||
}
|
||||
|
||||
@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")
|
||||
public void testImplicitAndExplicitLabeledThisInMember() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/parameters/extractThis/implicitAndExplicitLabeledThisInMember.kt");
|
||||
@@ -1667,6 +1673,12 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest {
|
||||
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")
|
||||
public void testQualifiedThisAsArgument() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/extractFunction/parameters/extractThis/qualifiedThisAsArgument.kt");
|
||||
|
||||
Reference in New Issue
Block a user