diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInliner/CodeToInlineBuilder.kt b/idea/src/org/jetbrains/kotlin/idea/codeInliner/CodeToInlineBuilder.kt index 65774e8c721..549bf7d2f31 100644 --- a/idea/src/org/jetbrains/kotlin/idea/codeInliner/CodeToInlineBuilder.kt +++ b/idea/src/org/jetbrains/kotlin/idea/codeInliner/CodeToInlineBuilder.kt @@ -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 = 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>() - codeToInline.forEachDescendantOfType { - 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>() diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/kotlinRefactoringUtil.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/kotlinRefactoringUtil.kt index bef5903d8d6..23cd9cd9f39 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/kotlinRefactoringUtil.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/kotlinRefactoringUtil.kt @@ -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] } diff --git a/idea/testData/refactoring/inline/function/expressionBody/explicitTypeArgument.kt b/idea/testData/refactoring/inline/function/expressionBody/explicitTypeArgument.kt new file mode 100644 index 00000000000..a8579a439db --- /dev/null +++ b/idea/testData/refactoring/inline/function/expressionBody/explicitTypeArgument.kt @@ -0,0 +1,5 @@ +fun bar(): List = listOf() + +fun f() { + val vv = bar() +} \ No newline at end of file diff --git a/idea/testData/refactoring/inline/function/expressionBody/explicitTypeArgument.kt.after b/idea/testData/refactoring/inline/function/expressionBody/explicitTypeArgument.kt.after new file mode 100644 index 00000000000..90a2daa93c2 --- /dev/null +++ b/idea/testData/refactoring/inline/function/expressionBody/explicitTypeArgument.kt.after @@ -0,0 +1,3 @@ +fun f() { + val vv = listOf() +} \ No newline at end of file diff --git a/idea/testData/refactoring/inline/function/expressionBody/explicitTypeArgumentComplex.kt b/idea/testData/refactoring/inline/function/expressionBody/explicitTypeArgumentComplex.kt new file mode 100644 index 00000000000..84b7657fed9 --- /dev/null +++ b/idea/testData/refactoring/inline/function/expressionBody/explicitTypeArgumentComplex.kt @@ -0,0 +1,10 @@ +interface SomeFace +interface GeneOut {} +object Empty : GeneOut +fun downUnder(): GeneOut = Empty +fun downParameter(p: GeneOut) = p + +fun callDown() { + // BUG: KT-17402 + val v2 = downParameter(downUnder()) +} \ No newline at end of file diff --git a/idea/testData/refactoring/inline/function/expressionBody/explicitTypeArgumentComplex.kt.after b/idea/testData/refactoring/inline/function/expressionBody/explicitTypeArgumentComplex.kt.after new file mode 100644 index 00000000000..b253891f80a --- /dev/null +++ b/idea/testData/refactoring/inline/function/expressionBody/explicitTypeArgumentComplex.kt.after @@ -0,0 +1,9 @@ +interface SomeFace +interface GeneOut {} +object Empty : GeneOut +fun downUnder(): GeneOut = Empty + +fun callDown() { + // BUG: KT-17402 + val v2 = downUnder() +} \ No newline at end of file diff --git a/idea/testData/refactoring/inline/function/expressionBody/explicitTypeArgumentNotNeeded.kt b/idea/testData/refactoring/inline/function/expressionBody/explicitTypeArgumentNotNeeded.kt new file mode 100644 index 00000000000..a338043e9db --- /dev/null +++ b/idea/testData/refactoring/inline/function/expressionBody/explicitTypeArgumentNotNeeded.kt @@ -0,0 +1,5 @@ +fun bar(): List = listOf() + +fun ff() { + val copy: List = ArrayList(bar()) +} diff --git a/idea/testData/refactoring/inline/function/expressionBody/explicitTypeArgumentNotNeeded.kt.after b/idea/testData/refactoring/inline/function/expressionBody/explicitTypeArgumentNotNeeded.kt.after new file mode 100644 index 00000000000..341812f590a --- /dev/null +++ b/idea/testData/refactoring/inline/function/expressionBody/explicitTypeArgumentNotNeeded.kt.after @@ -0,0 +1,3 @@ +fun ff() { + val copy: List = ArrayList(listOf()) +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/inline/InlineTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/refactoring/inline/InlineTestGenerated.java index 4076dc0f9f5..c494abd790c 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/inline/InlineTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/inline/InlineTestGenerated.java @@ -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");