"Convert to anonymous object" quickfix: false negative when interface has concrete members

#KT-37908 Fixed
This commit is contained in:
Toshiaki Kameyama
2020-04-01 12:49:46 +09:00
committed by Yan Zhulanow
parent 5b927d798c
commit 111b2945e1
7 changed files with 87 additions and 2 deletions
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.idea.quickfix
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.diagnostics.Diagnostic
@@ -20,7 +21,7 @@ import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.psi.KtReferenceExpression
import org.jetbrains.kotlin.resolve.calls.tower.WrongResolutionToClassifier
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyClassDescriptor
import org.jetbrains.kotlin.resolve.sam.getAbstractMembers
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
class ConvertToAnonymousObjectFix(element: KtNameReferenceExpression) : KotlinQuickFixAction<KtNameReferenceExpression>(element) {
@@ -52,6 +53,10 @@ class ConvertToAnonymousObjectFix(element: KtNameReferenceExpression) : KotlinQu
private fun getFunctionDescriptor(
d: DiagnosticWithParameters3<KtReferenceExpression, ClassifierDescriptor, WrongResolutionToClassifier, String>
) = (d.a as? LazyClassDescriptor)?.declaredCallableMembers?.singleOrNull() as? SimpleFunctionDescriptor
): SimpleFunctionDescriptor? {
val classDescriptor = d.a as? ClassDescriptor ?: return null
val singleAbstractFunction = getAbstractMembers(classDescriptor).singleOrNull() as? SimpleFunctionDescriptor ?: return null
return if (singleAbstractFunction.typeParameters.isEmpty()) singleAbstractFunction else null
}
}
}
@@ -0,0 +1,11 @@
// "Convert to anonymous object" "true"
interface I {
fun a()
fun b() {}
}
fun foo(i: I) {}
fun test() {
foo(<caret>I {})
}
@@ -0,0 +1,15 @@
// "Convert to anonymous object" "true"
interface I {
fun a()
fun b() {}
}
fun foo(i: I) {}
fun test() {
foo(object : I {
override fun a() {
}
})
}
@@ -0,0 +1,12 @@
// "Convert to anonymous object" "true"
interface I {
fun a()
val b: Int
get() = 1
}
fun foo(i: I) {}
fun test() {
foo(<caret>I {})
}
@@ -0,0 +1,16 @@
// "Convert to anonymous object" "true"
interface I {
fun a()
val b: Int
get() = 1
}
fun foo(i: I) {}
fun test() {
foo(object : I {
override fun a() {
}
})
}
@@ -0,0 +1,11 @@
// "Convert to anonymous object" "false"
// ERROR: Interface I does not have constructors
// ACTION: Introduce import alias
// ACTION: Split property declaration
interface I {
fun <T> foo(): String
}
fun test() {
val i = <caret>I { "" }
}
@@ -2911,6 +2911,21 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/quickfix/convertToAnonymousObject"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), null, true);
}
@TestMetadata("hasConcreateMember.kt")
public void testHasConcreateMember() throws Exception {
runTest("idea/testData/quickfix/convertToAnonymousObject/hasConcreateMember.kt");
}
@TestMetadata("hasConcreateMember2.kt")
public void testHasConcreateMember2() throws Exception {
runTest("idea/testData/quickfix/convertToAnonymousObject/hasConcreateMember2.kt");
}
@TestMetadata("hasTypeParameter.kt")
public void testHasTypeParameter() throws Exception {
runTest("idea/testData/quickfix/convertToAnonymousObject/hasTypeParameter.kt");
}
@TestMetadata("labeledReturn.kt")
public void testLabeledReturn() throws Exception {
runTest("idea/testData/quickfix/convertToAnonymousObject/labeledReturn.kt");