"Convert to anonymous object" intention: suggest for kotlin fun interface
#KT-37749 Fixed
This commit is contained in:
committed by
Roman Golyshev
parent
0abe3a6c39
commit
6a1923a477
+10
-8
@@ -15,11 +15,10 @@ import org.jetbrains.kotlin.idea.KotlinBundle
|
||||
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
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
|
||||
import org.jetbrains.kotlin.load.java.sam.JavaSingleAbstractMethodUtils
|
||||
import org.jetbrains.kotlin.psi.KtCallExpression
|
||||
import org.jetbrains.kotlin.psi.KtFunctionLiteral
|
||||
import org.jetbrains.kotlin.psi.KtLambdaExpression
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType
|
||||
@@ -39,13 +38,12 @@ class SamConversionToAnonymousObjectIntention : SelfTargetingRangeIntention<KtCa
|
||||
val callee = element.calleeExpression ?: return null
|
||||
val lambda = getLambdaExpression(element) ?: return null
|
||||
val functionLiteral = lambda.functionLiteral
|
||||
val descriptor = (functionLiteral.descriptor as? FunctionDescriptor) ?: return null
|
||||
val bindingContext = functionLiteral.analyze()
|
||||
val sam = element.getSingleAbstractMethod(bindingContext) ?: return null
|
||||
|
||||
val samValueParameters = sam.valueParameters
|
||||
val samValueParameterSize = samValueParameters.size
|
||||
if (descriptor.valueParameters.size != samValueParameterSize) return null
|
||||
if (samValueParameterSize != functionLiteral.functionDescriptor(bindingContext)?.valueParameters?.size) return null
|
||||
|
||||
val samName = sam.name.asString()
|
||||
if (functionLiteral.anyDescendantOfType<KtCallExpression> { call ->
|
||||
@@ -65,18 +63,22 @@ class SamConversionToAnonymousObjectIntention : SelfTargetingRangeIntention<KtCa
|
||||
|
||||
override fun applyTo(element: KtCallExpression, editor: Editor?) {
|
||||
val lambda = getLambdaExpression(element) ?: return
|
||||
val functionDescriptor = lambda.functionLiteral.descriptor as? FunctionDescriptor ?: return
|
||||
val functionName = element.getSingleAbstractMethod(element.analyze(BodyResolveMode.PARTIAL))?.name?.asString() ?: return
|
||||
val context = element.analyze(BodyResolveMode.PARTIAL)
|
||||
val functionDescriptor = lambda.functionLiteral.functionDescriptor(context) ?: return
|
||||
val functionName = element.getSingleAbstractMethod(context)?.name?.asString() ?: return
|
||||
convertToAnonymousObject(element, lambda, functionDescriptor, functionName)
|
||||
}
|
||||
|
||||
private fun KtCallExpression.getSingleAbstractMethod(context: BindingContext): FunctionDescriptor? {
|
||||
val type = getType(context) ?: return null
|
||||
if (!JavaSingleAbstractMethodUtils.isSamType(type)) return null
|
||||
val javaClass = type.constructor.declarationDescriptor as? JavaClassDescriptor ?: return null
|
||||
return getSingleAbstractMethodOrNull(javaClass)
|
||||
val classDescriptor = type.constructor.declarationDescriptor as? ClassDescriptor ?: return null
|
||||
return getSingleAbstractMethodOrNull(classDescriptor)
|
||||
}
|
||||
|
||||
private fun KtFunctionLiteral.functionDescriptor(context: BindingContext): FunctionDescriptor? =
|
||||
context[BindingContext.DECLARATION_TO_DESCRIPTOR, this] as? FunctionDescriptor
|
||||
|
||||
companion object {
|
||||
fun convertToAnonymousObject(
|
||||
call: KtCallExpression,
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
fun interface KotlinFace {
|
||||
fun single()
|
||||
}
|
||||
|
||||
fun useSam(kf: KotlinFace) {}
|
||||
|
||||
fun callSam() {
|
||||
useSam(kf = <caret>KotlinFace {})
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
fun interface KotlinFace {
|
||||
fun single()
|
||||
}
|
||||
|
||||
fun useSam(kf: KotlinFace) {}
|
||||
|
||||
fun callSam() {
|
||||
useSam(kf = object : KotlinFace {
|
||||
override fun single() {
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -14790,6 +14790,11 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/intentions/samConversionToAnonymousObject"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), null, true);
|
||||
}
|
||||
|
||||
@TestMetadata("funInterface.kt")
|
||||
public void testFunInterface() throws Exception {
|
||||
runTest("idea/testData/intentions/samConversionToAnonymousObject/funInterface.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("labeledReturn.kt")
|
||||
public void testLabeledReturn() throws Exception {
|
||||
runTest("idea/testData/intentions/samConversionToAnonymousObject/labeledReturn.kt");
|
||||
|
||||
Reference in New Issue
Block a user