Inline refactoring: should add explicit type argument for parameters

#KT-17402 Fixed
This commit is contained in:
Dmitry Gridin
2020-06-26 10:11:50 +07:00
parent 45234c9784
commit c3b726f10a
14 changed files with 111 additions and 11 deletions
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
import org.jetbrains.kotlin.idea.core.* import org.jetbrains.kotlin.idea.core.*
import org.jetbrains.kotlin.idea.inspections.RedundantUnitExpressionInspection import org.jetbrains.kotlin.idea.inspections.RedundantUnitExpressionInspection
import org.jetbrains.kotlin.idea.intentions.InsertExplicitTypeArgumentsIntention
import org.jetbrains.kotlin.idea.intentions.RemoveExplicitTypeArgumentsIntention import org.jetbrains.kotlin.idea.intentions.RemoveExplicitTypeArgumentsIntention
import org.jetbrains.kotlin.idea.util.CommentSaver import org.jetbrains.kotlin.idea.util.CommentSaver
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
@@ -35,6 +36,7 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.isError import org.jetbrains.kotlin.types.isError
import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class CodeInliner<TCallElement : KtElement>( class CodeInliner<TCallElement : KtElement>(
private val nameExpression: KtSimpleNameExpression, private val nameExpression: KtSimpleNameExpression,
@@ -175,7 +177,13 @@ class CodeInliner<TCallElement : KtElement>(
for (parameter in descriptor.valueParameters.asReversed()) { for (parameter in descriptor.valueParameters.asReversed()) {
val argument = argumentForParameter(parameter, descriptor) ?: continue val argument = argumentForParameter(parameter, descriptor) ?: continue
argument.expression.put(PARAMETER_VALUE_KEY, parameter) val expression = argument.expression.apply {
if (this is KtCallElement) {
insertExplicitTypeArgument()
}
put(PARAMETER_VALUE_KEY, parameter)
}
val parameterName = parameter.name val parameterName = parameter.name
val usages = codeToInline.collectDescendantsOfType<KtExpression> { val usages = codeToInline.collectDescendantsOfType<KtExpression> {
@@ -191,19 +199,30 @@ class CodeInliner<TCallElement : KtElement>(
usageArgument?.mark(DEFAULT_PARAMETER_VALUE_KEY) usageArgument?.mark(DEFAULT_PARAMETER_VALUE_KEY)
} }
codeToInline.replaceExpression(it, argument.expression.copied()) codeToInline.replaceExpression(it, expression.copied())
} }
//TODO: sometimes we need to add explicit type arguments here because we don't have expected type in the new context if (expression.shouldKeepValue(usageCount = usages.size)) {
introduceValuesForParameters.add(IntroduceValueForParameter(parameter, expression, argument.expressionType))
if (argument.expression.shouldKeepValue(usageCount = usages.size)) {
introduceValuesForParameters.add(IntroduceValueForParameter(parameter, argument.expression, argument.expressionType))
} }
} }
return introduceValuesForParameters return introduceValuesForParameters
} }
private fun KtCallElement.insertExplicitTypeArgument() {
if (InsertExplicitTypeArgumentsIntention.isApplicableTo(this, bindingContext)) {
InsertExplicitTypeArgumentsIntention.createTypeArguments(this, bindingContext)?.let { typeArgumentList ->
clear(USER_CODE_KEY)
for (child in children) {
child.safeAs<KtElement>()?.mark(USER_CODE_KEY)
}
addAfter(typeArgumentList, calleeExpression)
}
}
}
private data class IntroduceValueForParameter( private data class IntroduceValueForParameter(
val parameter: ValueParameterDescriptor, val parameter: ValueParameterDescriptor,
val value: KtExpression, val value: KtExpression,
@@ -11,7 +11,7 @@ fun oldFun(p: List<String>) {
fun newFun(p1: List<String>, p2: List<String>){} fun newFun(p1: List<String>, p2: List<String>){}
fun foo() { fun foo() {
val p: List<String> = bar() val p = bar<String>()
<caret>newFun(p, p) <caret>newFun(p, p)
} }
@@ -0,0 +1,8 @@
interface SomeFace
interface GeneOut<out T> {}
object Empty : GeneOut<Nothing>
fun <T> downUnder(): GeneOut<T> = Empty
fun downReturn<caret>(): GeneOut<SomeFace> = downUnder()
fun callDown() {
val v1 = downReturn()
}
@@ -0,0 +1,7 @@
interface SomeFace
interface GeneOut<out T> {}
object Empty : GeneOut<Nothing>
fun <T> downUnder(): GeneOut<T> = Empty
fun callDown() {
val v1 = downUnder<SomeFace>()
}
@@ -5,6 +5,5 @@ fun <T> downUnder(): GeneOut<T> = Empty
fun downParameter(p: GeneOut<SomeFace>) = p fun downParameter(p: GeneOut<SomeFace>) = p
fun callDown() { fun callDown() {
// BUG: KT-17402
val v2 = <caret>downParameter(downUnder()) val v2 = <caret>downParameter(downUnder())
} }
@@ -4,6 +4,5 @@ object Empty : GeneOut<Nothing>
fun <T> downUnder(): GeneOut<T> = Empty fun <T> downUnder(): GeneOut<T> = Empty
fun callDown() { fun callDown() {
// BUG: KT-17402 val v2 = downUnder<SomeFace>()
val v2 = downUnder()
} }
@@ -0,0 +1,13 @@
package test.pack.one
interface SomeFace
interface GeneOut<out T> {}
object Empty : GeneOut<Nothing>
fun <T> downUnder(): GeneOut<T> = Empty
fun downParameter<caret>(p: GeneOut<SomeFace>): GeneOut<SomeFace> {
p
return p
}
fun callDown() {
val v2 = downParameter(downUnder())
}
@@ -0,0 +1,11 @@
package test.pack.one
interface SomeFace
interface GeneOut<out T> {}
object Empty : GeneOut<Nothing>
fun <T> downUnder(): GeneOut<T> = Empty
fun callDown() {
val p = downUnder<SomeFace>()
p
val v2 = p
}
@@ -0,0 +1,7 @@
package test.pack.one
interface SomeFace
interface GeneOut<out T> {}
object Empty : GeneOut<Nothing>
fun <T> downUnder(): GeneOut<T> = Empty
fun downParameter(p: GeneOut<SomeFace>): GeneOut<SomeFace> = p
@@ -0,0 +1,6 @@
package test.pack.one
interface SomeFace
interface GeneOut<out T> {}
object Empty : GeneOut<Nothing>
fun <T> downUnder(): GeneOut<T> = Empty
@@ -0,0 +1,8 @@
package adadawwq32q
import test.pack.one.downParameter
import test.pack.one.downUnder
fun callDown() {
val result = downParameter<caret>(downUnder())
}
@@ -0,0 +1,8 @@
package adadawwq32q
import test.pack.one.SomeFace
import test.pack.one.downUnder
fun callDown() {
val result = downUnder<SomeFace>()
}
@@ -3,4 +3,4 @@ fun g() {
if (it.isEmpty()) return@any false if (it.isEmpty()) return@any false
it.length < 10 it.length < 10
}) })
} }
@@ -237,6 +237,11 @@ public class InlineTestGenerated extends AbstractInlineTest {
runTest("idea/testData/refactoring/inline/function/expressionBody/FunctionalType.kt"); runTest("idea/testData/refactoring/inline/function/expressionBody/FunctionalType.kt");
} }
@TestMetadata("GenericTypeArgument.kt")
public void testGenericTypeArgument() throws Exception {
runTest("idea/testData/refactoring/inline/function/expressionBody/GenericTypeArgument.kt");
}
@TestMetadata("Lambda.kt") @TestMetadata("Lambda.kt")
public void testLambda() throws Exception { public void testLambda() throws Exception {
runTest("idea/testData/refactoring/inline/function/expressionBody/Lambda.kt"); runTest("idea/testData/refactoring/inline/function/expressionBody/Lambda.kt");
@@ -448,6 +453,16 @@ public class InlineTestGenerated extends AbstractInlineTest {
runTest("idea/testData/refactoring/inline/function/returnAtEnd/DefaultParameter.kt"); runTest("idea/testData/refactoring/inline/function/returnAtEnd/DefaultParameter.kt");
} }
@TestMetadata("GenericTypeArgument.kt")
public void testGenericTypeArgument() throws Exception {
runTest("idea/testData/refactoring/inline/function/returnAtEnd/GenericTypeArgument.kt");
}
@TestMetadata("GenericTypeArgument2.kt")
public void testGenericTypeArgument2() throws Exception {
runTest("idea/testData/refactoring/inline/function/returnAtEnd/GenericTypeArgument2.kt");
}
@TestMetadata("InnerFunction.kt") @TestMetadata("InnerFunction.kt")
public void testInnerFunction() throws Exception { public void testInnerFunction() throws Exception {
runTest("idea/testData/refactoring/inline/function/returnAtEnd/InnerFunction.kt"); runTest("idea/testData/refactoring/inline/function/returnAtEnd/InnerFunction.kt");