diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/refactoring/introduce/ExtractionTestGenerated.java b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/refactoring/introduce/ExtractionTestGenerated.java index 9a55542614bf..3cf7d73b067c 100644 --- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/refactoring/introduce/ExtractionTestGenerated.java +++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/idea/refactoring/introduce/ExtractionTestGenerated.java @@ -2491,6 +2491,16 @@ public abstract class ExtractionTestGenerated extends AbstractExtractionTest { runTest("testData/refactoring/extractFunction/parameters/misc/runQualifier.kt"); } + @TestMetadata("smartCastInside.kt") + public void testSmartCastInside() throws Exception { + runTest("testData/refactoring/extractFunction/parameters/misc/smartCastInside.kt"); + } + + @TestMetadata("smartCastInside1.kt") + public void testSmartCastInside1() throws Exception { + runTest("testData/refactoring/extractFunction/parameters/misc/smartCastInside1.kt"); + } + @TestMetadata("thisInObject.kt") public void testThisInObject() throws Exception { runTest("testData/refactoring/extractFunction/parameters/misc/thisInObject.kt"); diff --git a/plugins/kotlin/idea/tests/testData/refactoring/extractFunction/parameters/misc/smartCastInside.kt b/plugins/kotlin/idea/tests/testData/refactoring/extractFunction/parameters/misc/smartCastInside.kt new file mode 100644 index 000000000000..b92fef8b9590 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/refactoring/extractFunction/parameters/misc/smartCastInside.kt @@ -0,0 +1,11 @@ +class X(val field: Any?) + +fun foo(list: List) { + for (x in list) { + if (x.field != null) { + println(x.field.hashCode()) + } + } +} + +// IGNORE_K1 \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/refactoring/extractFunction/parameters/misc/smartCastInside.kt.after b/plugins/kotlin/idea/tests/testData/refactoring/extractFunction/parameters/misc/smartCastInside.kt.after new file mode 100644 index 000000000000..50b3bb79c61c --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/refactoring/extractFunction/parameters/misc/smartCastInside.kt.after @@ -0,0 +1,15 @@ +class X(val field: Any?) + +fun foo(list: List) { + __dummyTestFun__(list) +} + +private fun __dummyTestFun__(list: List) { + for (x in list) { + if (x.field != null) { + println(x.field.hashCode()) + } + } +} + +// IGNORE_K1 \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/refactoring/extractFunction/parameters/misc/smartCastInside1.kt b/plugins/kotlin/idea/tests/testData/refactoring/extractFunction/parameters/misc/smartCastInside1.kt new file mode 100644 index 000000000000..11798d407759 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/refactoring/extractFunction/parameters/misc/smartCastInside1.kt @@ -0,0 +1,9 @@ +class C(val int: Int?) + +fun test(x: Int, c: C): Int { + val a = + if (c.int != null) x + c.int else x + return a * a +} + +// IGNORE_K1 \ No newline at end of file diff --git a/plugins/kotlin/idea/tests/testData/refactoring/extractFunction/parameters/misc/smartCastInside1.kt.after b/plugins/kotlin/idea/tests/testData/refactoring/extractFunction/parameters/misc/smartCastInside1.kt.after new file mode 100644 index 000000000000..6449f80d5ac7 --- /dev/null +++ b/plugins/kotlin/idea/tests/testData/refactoring/extractFunction/parameters/misc/smartCastInside1.kt.after @@ -0,0 +1,11 @@ +class C(val int: Int?) + +fun test(x: Int, c: C): Int { + val a = + i(c, x) + return a * a +} + +private fun i(c: C, x: Int): Int = if (c.int != null) x + c.int else x + +// IGNORE_K1 \ No newline at end of file diff --git a/plugins/kotlin/refactorings/kotlin.refactorings.k2/src/org/jetbrains/kotlin/idea/k2/refactoring/extractFunction/parametersUtil.kt b/plugins/kotlin/refactorings/kotlin.refactorings.k2/src/org/jetbrains/kotlin/idea/k2/refactoring/extractFunction/parametersUtil.kt index 370f5fd89e13..d73120c6b729 100644 --- a/plugins/kotlin/refactorings/kotlin.refactorings.k2/src/org/jetbrains/kotlin/idea/k2/refactoring/extractFunction/parametersUtil.kt +++ b/plugins/kotlin/refactorings/kotlin.refactorings.k2/src/org/jetbrains/kotlin/idea/k2/refactoring/extractFunction/parametersUtil.kt @@ -84,6 +84,7 @@ import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis import org.jetbrains.kotlin.psi.psiUtil.isInsideOf import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.expressions.OperatorConventions +import org.jetbrains.kotlin.idea.k2.refactoring.introduce.K2SemanticMatcher.isSemanticMatch context(KtAnalysisSession) internal fun ExtractionData.inferParametersInfo( @@ -416,6 +417,7 @@ private fun createOriginalType( private fun ExtractionData.getBrokenReferencesInfo(body: KtBlockExpression): List> { val newReferences = body.collectDescendantsOfType { it.resolveResult != null } + val smartCastPossibleRoots = mutableSetOf() val referencesInfo = ArrayList>() for (newRef in newReferences) { val originalResolveResult = newRef.resolveResult as? ResolveResult ?: continue @@ -428,7 +430,21 @@ private fun ExtractionData.getBrokenReferencesInfo(body: KtBlockExpression): Lis val qualifiedExpression = newRef.getQualifiedExpressionForSelector() if (qualifiedExpression != null) { val smartCastTarget = originalRefExpr.parent as KtExpression - smartCast = analyze(smartCastTarget) { smartCastTarget.getSmartCastInfo()?.smartCastType } + smartCast = analyze(smartCastTarget) { + val cast = smartCastTarget.getSmartCastInfo()?.smartCastType + when { + cast == null -> { + smartCastPossibleRoots.add(smartCastTarget) + null + } + + //same qualified expressions without smartcast are present in the code fragment, + //so smart cast is done inside selection, no need to extract additional parameter + smartCastPossibleRoots.any { it.isSemanticMatch(smartCastTarget) } -> null + else -> cast + } + } + possibleTypes = analyze(smartCastTarget) { smartCastTarget.getExpectedType()?.let { setOf(it) } ?: emptySet() } val (isCompanionObject, bothReceivers) = analyze(smartCastTarget) { val symbol = originalRefExpr.resolveCall()?.singleCallOrNull>()?.partiallyAppliedSymbol diff --git a/plugins/kotlin/refactorings/kotlin.refactorings.tests.k2/test/org/jetbrains/kotlin/idea/k2/refactoring/introduceFunction/K2IntroduceFunctionTestGenerated.java b/plugins/kotlin/refactorings/kotlin.refactorings.tests.k2/test/org/jetbrains/kotlin/idea/k2/refactoring/introduceFunction/K2IntroduceFunctionTestGenerated.java index 952426f44d1a..def046b7cda2 100644 --- a/plugins/kotlin/refactorings/kotlin.refactorings.tests.k2/test/org/jetbrains/kotlin/idea/k2/refactoring/introduceFunction/K2IntroduceFunctionTestGenerated.java +++ b/plugins/kotlin/refactorings/kotlin.refactorings.tests.k2/test/org/jetbrains/kotlin/idea/k2/refactoring/introduceFunction/K2IntroduceFunctionTestGenerated.java @@ -1649,6 +1649,16 @@ public abstract class K2IntroduceFunctionTestGenerated extends AbstractK2Introdu runTest("../../idea/tests/testData/refactoring/extractFunction/parameters/misc/runQualifier.kt"); } + @TestMetadata("smartCastInside.kt") + public void testSmartCastInside() throws Exception { + runTest("../../idea/tests/testData/refactoring/extractFunction/parameters/misc/smartCastInside.kt"); + } + + @TestMetadata("smartCastInside1.kt") + public void testSmartCastInside1() throws Exception { + runTest("../../idea/tests/testData/refactoring/extractFunction/parameters/misc/smartCastInside1.kt"); + } + @TestMetadata("thisInObject.kt") public void testThisInObject() throws Exception { runTest("../../idea/tests/testData/refactoring/extractFunction/parameters/misc/thisInObject.kt");