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.core.*
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.util.CommentSaver
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.isError
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
class CodeInliner<TCallElement : KtElement>(
private val nameExpression: KtSimpleNameExpression,
@@ -175,7 +177,13 @@ class CodeInliner<TCallElement : KtElement>(
for (parameter in descriptor.valueParameters.asReversed()) {
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 usages = codeToInline.collectDescendantsOfType<KtExpression> {
@@ -191,19 +199,30 @@ class CodeInliner<TCallElement : KtElement>(
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 (argument.expression.shouldKeepValue(usageCount = usages.size)) {
introduceValuesForParameters.add(IntroduceValueForParameter(parameter, argument.expression, argument.expressionType))
if (expression.shouldKeepValue(usageCount = usages.size)) {
introduceValuesForParameters.add(IntroduceValueForParameter(parameter, expression, argument.expressionType))
}
}
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(
val parameter: ValueParameterDescriptor,
val value: KtExpression,
@@ -11,7 +11,7 @@ fun oldFun(p: List<String>) {
fun newFun(p1: List<String>, p2: List<String>){}
fun foo() {
val p: List<String> = bar()
val p = bar<String>()
<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 callDown() {
// BUG: KT-17402
val v2 = <caret>downParameter(downUnder())
}
@@ -4,6 +4,5 @@ object Empty : GeneOut<Nothing>
fun <T> downUnder(): GeneOut<T> = Empty
fun callDown() {
// BUG: KT-17402
val v2 = downUnder()
val v2 = downUnder<SomeFace>()
}
@@ -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
it.length < 10
})
}
}
@@ -237,6 +237,11 @@ public class InlineTestGenerated extends AbstractInlineTest {
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")
public void testLambda() throws Exception {
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");
}
@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")
public void testInnerFunction() throws Exception {
runTest("idea/testData/refactoring/inline/function/returnAtEnd/InnerFunction.kt");