Convert to anonymous object: fix wrong replacement when SAM is nested interface

#KT-33660 Fixed
This commit is contained in:
Toshiaki Kameyama
2019-10-01 08:14:23 +09:00
committed by Dmitry Gridin
parent 2e3428bbe7
commit 6a329210cb
6 changed files with 43 additions and 2 deletions
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.diagnostics.Severity
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor
import org.jetbrains.kotlin.lexer.KtTokens
@@ -21,8 +22,10 @@ import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtLambdaExpression
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelector
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
@@ -84,7 +87,12 @@ class SamConversionToAnonymousObjectIntention : SelfTargetingRangeIntention<KtCa
functionDescriptor: FunctionDescriptor,
functionName: String
) {
val interfaceName = call.calleeExpression?.text ?: return
val parentOfCall = call.getQualifiedExpressionForSelector()
val interfaceName = if (parentOfCall != null) {
parentOfCall.resolveToCall()?.resultingDescriptor?.fqNameSafe?.asString()
} else {
call.calleeExpression?.text
} ?: return
val typeArguments = call.typeArguments.mapNotNull { it.typeReference }
val typeArgumentsText =
if (typeArguments.isEmpty()) "" else typeArguments.joinToString(prefix = "<", postfix = ">", separator = ", ") { it.text }
@@ -92,7 +100,9 @@ class SamConversionToAnonymousObjectIntention : SelfTargetingRangeIntention<KtCa
val typeParameters = classDescriptor?.declaredTypeParameters?.map { it.name.asString() }?.zip(typeArguments)?.toMap().orEmpty()
LambdaToAnonymousFunctionIntention.convertLambdaToFunction(lambda, functionDescriptor, functionName, typeParameters) {
it.addModifier(KtTokens.OVERRIDE_KEYWORD)
call.replaced(KtPsiFactory(it).createExpression("object : $interfaceName$typeArgumentsText { ${it.text} }"))
(parentOfCall ?: call).replaced(
KtPsiFactory(it).createExpression("object : $interfaceName$typeArgumentsText { ${it.text} }")
)
}
}
@@ -0,0 +1,8 @@
public class J {
public void foo(Sam sam) {
}
public interface Sam {
void bar();
}
}
@@ -0,0 +1,8 @@
public class J {
public void foo(Sam sam) {
}
public interface Sam {
void bar();
}
}
@@ -0,0 +1,3 @@
fun main() {
J().foo(J.Sam<caret> {})
}
@@ -0,0 +1,7 @@
fun main() {
J().foo(object : J.Sam {
override fun bar() {
}
})
}
@@ -14652,6 +14652,11 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
runTest("idea/testData/intentions/samConversionToAnonymousObject/labeledReturn_ni.kt");
}
@TestMetadata("nestedClass.kt")
public void testNestedClass() throws Exception {
runTest("idea/testData/intentions/samConversionToAnonymousObject/nestedClass.kt");
}
@TestMetadata("notJavaInterface.kt")
public void testNotJavaInterface() throws Exception {
runTest("idea/testData/intentions/samConversionToAnonymousObject/notJavaInterface.kt");