Add type arguments more accurately during inlining
This commit is contained in:
@@ -25,6 +25,8 @@ import org.jetbrains.kotlin.idea.core.asExpression
|
||||
import org.jetbrains.kotlin.idea.imports.importableFqName
|
||||
import org.jetbrains.kotlin.idea.intentions.InsertExplicitTypeArgumentsIntention
|
||||
import org.jetbrains.kotlin.idea.intentions.SpecifyExplicitLambdaSignatureIntention
|
||||
import org.jetbrains.kotlin.idea.refactoring.addTypeArgumentsIfNeeded
|
||||
import org.jetbrains.kotlin.idea.refactoring.getQualifiedTypeArgumentList
|
||||
import org.jetbrains.kotlin.idea.references.canBeResolvedViaImport
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||
@@ -57,15 +59,13 @@ class CodeToInlineBuilder(
|
||||
analyze: () -> BindingContext,
|
||||
importFqNames: Collection<FqName> = emptyList()
|
||||
): CodeToInline {
|
||||
var bindingContext = analyze()
|
||||
val bindingContext = analyze()
|
||||
|
||||
val codeToInline = MutableCodeToInline(mainExpression, statementsBefore.toMutableList(), importFqNames.toMutableSet())
|
||||
|
||||
bindingContext = insertExplicitTypeArguments(codeToInline, bindingContext, analyze)
|
||||
|
||||
insertExplicitReceivers(codeToInline, bindingContext)
|
||||
|
||||
if (mainExpression != null) {
|
||||
if (mainExpression != null && mainExpression in codeToInline) {
|
||||
val functionLiteralExpression = mainExpression.unpackFunctionLiteral(true)
|
||||
if (functionLiteralExpression != null) {
|
||||
val functionLiteralParameterTypes = getParametersForFunctionLiteral(functionLiteralExpression, bindingContext)
|
||||
@@ -75,8 +75,15 @@ class CodeToInlineBuilder(
|
||||
}
|
||||
}
|
||||
}
|
||||
val typeArgumentsForCall = getQualifiedTypeArgumentList(mainExpression, bindingContext)
|
||||
if (typeArgumentsForCall != null) {
|
||||
codeToInline.addPostInsertionAction(mainExpression) { inlinedExpression ->
|
||||
addTypeArgumentsIfNeeded(inlinedExpression, typeArgumentsForCall)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return codeToInline.toNonMutable()
|
||||
}
|
||||
|
||||
@@ -117,24 +124,6 @@ class CodeToInlineBuilder(
|
||||
}
|
||||
}
|
||||
|
||||
private fun insertExplicitTypeArguments(codeToInline: MutableCodeToInline, bindingContext: BindingContext, analyze: () -> BindingContext): BindingContext {
|
||||
val typeArgsToAdd = ArrayList<Pair<KtCallExpression, KtTypeArgumentList>>()
|
||||
codeToInline.forEachDescendantOfType<KtCallExpression> {
|
||||
if (InsertExplicitTypeArgumentsIntention.isApplicableTo(it, bindingContext)) {
|
||||
typeArgsToAdd.add(it to InsertExplicitTypeArgumentsIntention.createTypeArguments(it, bindingContext)!!)
|
||||
}
|
||||
}
|
||||
|
||||
if (typeArgsToAdd.isEmpty()) return bindingContext
|
||||
|
||||
for ((callExpr, typeArgs) in typeArgsToAdd) {
|
||||
callExpr.addAfter(typeArgs, callExpr.calleeExpression)
|
||||
}
|
||||
|
||||
// reanalyze expression - new usages of type parameters may be added
|
||||
return analyze()
|
||||
}
|
||||
|
||||
private fun insertExplicitReceivers(codeToInline: MutableCodeToInline, bindingContext: BindingContext) {
|
||||
val receiversToAdd = ArrayList<Pair<KtExpression, KtExpression>>()
|
||||
|
||||
|
||||
@@ -778,8 +778,10 @@ fun dropOverrideKeywordIfNecessary(element: KtNamedDeclaration) {
|
||||
}
|
||||
}
|
||||
|
||||
fun getQualifiedTypeArgumentList(initializer: KtExpression): KtTypeArgumentList? {
|
||||
val context = initializer.analyze(BodyResolveMode.PARTIAL)
|
||||
fun getQualifiedTypeArgumentList(
|
||||
initializer: KtExpression,
|
||||
context: BindingContext = initializer.analyze(BodyResolveMode.PARTIAL)
|
||||
): KtTypeArgumentList? {
|
||||
val call = initializer.getResolvedCall(context) ?: return null
|
||||
val typeArgumentMap = call.typeArguments
|
||||
val typeArguments = call.candidateDescriptor.typeParameters.mapNotNull { typeArgumentMap[it] }
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
fun bar(): List<Int> = listOf()
|
||||
|
||||
fun f() {
|
||||
val vv = <caret>bar()
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
fun f() {
|
||||
val vv = listOf<Int>()
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
interface SomeFace
|
||||
interface GeneOut<out T> {}
|
||||
object Empty : GeneOut<Nothing>
|
||||
fun <T> downUnder(): GeneOut<T> = Empty
|
||||
fun downParameter(p: GeneOut<SomeFace>) = p
|
||||
|
||||
fun callDown() {
|
||||
// BUG: KT-17402
|
||||
val v2 = <caret>downParameter(downUnder())
|
||||
}
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
interface SomeFace
|
||||
interface GeneOut<out T> {}
|
||||
object Empty : GeneOut<Nothing>
|
||||
fun <T> downUnder(): GeneOut<T> = Empty
|
||||
|
||||
fun callDown() {
|
||||
// BUG: KT-17402
|
||||
val v2 = downUnder()
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
fun bar(): List<Int> = listOf()
|
||||
|
||||
fun ff() {
|
||||
val copy: List<Int> = ArrayList(<caret>bar())
|
||||
}
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
fun ff() {
|
||||
val copy: List<Int> = ArrayList(listOf())
|
||||
}
|
||||
@@ -124,6 +124,24 @@ public class InlineTestGenerated extends AbstractInlineTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("explicitTypeArgument.kt")
|
||||
public void testExplicitTypeArgument() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/function/expressionBody/explicitTypeArgument.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("explicitTypeArgumentComplex.kt")
|
||||
public void testExplicitTypeArgumentComplex() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/function/expressionBody/explicitTypeArgumentComplex.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("explicitTypeArgumentNotNeeded.kt")
|
||||
public void testExplicitTypeArgumentNotNeeded() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/function/expressionBody/explicitTypeArgumentNotNeeded.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("FromUsage.kt")
|
||||
public void testFromUsage() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/function/expressionBody/FromUsage.kt");
|
||||
|
||||
Reference in New Issue
Block a user