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.imports.importableFqName
|
||||||
import org.jetbrains.kotlin.idea.intentions.InsertExplicitTypeArgumentsIntention
|
import org.jetbrains.kotlin.idea.intentions.InsertExplicitTypeArgumentsIntention
|
||||||
import org.jetbrains.kotlin.idea.intentions.SpecifyExplicitLambdaSignatureIntention
|
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.canBeResolvedViaImport
|
||||||
import org.jetbrains.kotlin.idea.references.mainReference
|
import org.jetbrains.kotlin.idea.references.mainReference
|
||||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||||
@@ -57,15 +59,13 @@ class CodeToInlineBuilder(
|
|||||||
analyze: () -> BindingContext,
|
analyze: () -> BindingContext,
|
||||||
importFqNames: Collection<FqName> = emptyList()
|
importFqNames: Collection<FqName> = emptyList()
|
||||||
): CodeToInline {
|
): CodeToInline {
|
||||||
var bindingContext = analyze()
|
val bindingContext = analyze()
|
||||||
|
|
||||||
val codeToInline = MutableCodeToInline(mainExpression, statementsBefore.toMutableList(), importFqNames.toMutableSet())
|
val codeToInline = MutableCodeToInline(mainExpression, statementsBefore.toMutableList(), importFqNames.toMutableSet())
|
||||||
|
|
||||||
bindingContext = insertExplicitTypeArguments(codeToInline, bindingContext, analyze)
|
|
||||||
|
|
||||||
insertExplicitReceivers(codeToInline, bindingContext)
|
insertExplicitReceivers(codeToInline, bindingContext)
|
||||||
|
|
||||||
if (mainExpression != null) {
|
if (mainExpression != null && mainExpression in codeToInline) {
|
||||||
val functionLiteralExpression = mainExpression.unpackFunctionLiteral(true)
|
val functionLiteralExpression = mainExpression.unpackFunctionLiteral(true)
|
||||||
if (functionLiteralExpression != null) {
|
if (functionLiteralExpression != null) {
|
||||||
val functionLiteralParameterTypes = getParametersForFunctionLiteral(functionLiteralExpression, bindingContext)
|
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()
|
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) {
|
private fun insertExplicitReceivers(codeToInline: MutableCodeToInline, bindingContext: BindingContext) {
|
||||||
val receiversToAdd = ArrayList<Pair<KtExpression, KtExpression>>()
|
val receiversToAdd = ArrayList<Pair<KtExpression, KtExpression>>()
|
||||||
|
|
||||||
|
|||||||
@@ -778,8 +778,10 @@ fun dropOverrideKeywordIfNecessary(element: KtNamedDeclaration) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getQualifiedTypeArgumentList(initializer: KtExpression): KtTypeArgumentList? {
|
fun getQualifiedTypeArgumentList(
|
||||||
val context = initializer.analyze(BodyResolveMode.PARTIAL)
|
initializer: KtExpression,
|
||||||
|
context: BindingContext = initializer.analyze(BodyResolveMode.PARTIAL)
|
||||||
|
): KtTypeArgumentList? {
|
||||||
val call = initializer.getResolvedCall(context) ?: return null
|
val call = initializer.getResolvedCall(context) ?: return null
|
||||||
val typeArgumentMap = call.typeArguments
|
val typeArgumentMap = call.typeArguments
|
||||||
val typeArguments = call.candidateDescriptor.typeParameters.mapNotNull { typeArgumentMap[it] }
|
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);
|
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")
|
@TestMetadata("FromUsage.kt")
|
||||||
public void testFromUsage() throws Exception {
|
public void testFromUsage() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/function/expressionBody/FromUsage.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/inline/function/expressionBody/FromUsage.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user