diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/AddActualFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/AddActualFix.kt index 11b13ec07dd..f8b4dfc9336 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/AddActualFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/AddActualFix.kt @@ -28,20 +28,20 @@ import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.idea.core.ShortenReferences import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactory -import org.jetbrains.kotlin.psi.KtClassOrObject -import org.jetbrains.kotlin.psi.KtElement -import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.psi.KtPsiFactory +import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils class AddActualFix( actualClassOrObject: KtClassOrObject, - expectedClassOrObject: KtClassOrObject + expectedClassOrObject: KtClassOrObject, + missedDeclarations: List ) : KotlinQuickFixAction(actualClassOrObject) { private val expectedClassPointer = expectedClassOrObject.createSmartPointer() + private val missedDeclarationPointers = missedDeclarations.map { it.createSmartPointer() } + override fun getFamilyName() = text override fun getText() = "Add missing actual members" @@ -49,12 +49,12 @@ class AddActualFix( override fun invoke(project: Project, editor: Editor?, file: KtFile) { val element = element ?: return val expectedClass = expectedClassPointer.element ?: return + val missedDeclarations = missedDeclarationPointers.mapNotNull { it.element } + if (missedDeclarations.isEmpty()) return val factory = KtPsiFactory(element) val pureActualClass = factory.generateClassOrObjectByExpectedClass( project, expectedClass, actualNeeded = true, - existingDeclarations = element.declarations + - element.primaryConstructor?.valueParameters?.filter { it.hasValOrVar() }.orEmpty() + - listOfNotNull(element.primaryConstructor) + missedDeclarations = missedDeclarations ) fun PsiElement.clean() { @@ -74,11 +74,20 @@ class AddActualFix( companion object : KotlinSingleIntentionActionFactory() { override fun createAction(diagnostic: Diagnostic): IntentionAction? { val incompatibleMap = DiagnosticFactory.cast(diagnostic, Errors.NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS).b + val expectedClassDescriptor = incompatibleMap.firstOrNull()?.first?.containingDeclaration as? ClassDescriptor ?: return null val expectedClassOrObject = DescriptorToSourceUtils.descriptorToDeclaration(expectedClassDescriptor) as? KtClassOrObject ?: return null - return (diagnostic.psiElement as? KtClassOrObject)?.let { AddActualFix(it, expectedClassOrObject) } + + val missedDeclarations = incompatibleMap.mapNotNull { + DescriptorToSourceUtils.descriptorToDeclaration(it.first) as? KtDeclaration + } + if (missedDeclarations.isEmpty()) return null + + return (diagnostic.psiElement as? KtClassOrObject)?.let { + AddActualFix(it, expectedClassOrObject, missedDeclarations) + } } } } \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/CreateActualFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/CreateActualFix.kt index 18ee46d42d3..59567e7bc04 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/CreateActualFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/CreateActualFix.kt @@ -223,7 +223,8 @@ internal fun KtPsiFactory.generateClassOrObjectByExpectedClass( project: Project, expectedClass: KtClassOrObject, actualNeeded: Boolean, - existingDeclarations: List = emptyList() + // If null, all expect class declarations are missed (so none from them exists) + missedDeclarations: List? = null ): KtClassOrObject { fun areCompatible(first: KtFunction, second: KtFunction) = first.valueParameters.size == second.valueParameters.size && @@ -232,7 +233,7 @@ internal fun KtPsiFactory.generateClassOrObjectByExpectedClass( } fun KtDeclaration.exists() = - existingDeclarations.any { + missedDeclarations != null && missedDeclarations.none { name == it.name && when (this) { is KtConstructor<*> -> it is KtConstructor<*> && areCompatible(this, it) is KtNamedFunction -> it is KtNamedFunction && areCompatible(this, it) diff --git a/idea/testData/multiModuleQuickFix/classFunctionSameSignature/common/common.kt b/idea/testData/multiModuleQuickFix/classFunctionSameSignature/common/common.kt new file mode 100644 index 00000000000..fa6c82ec103 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/classFunctionSameSignature/common/common.kt @@ -0,0 +1,5 @@ +// DISABLE-ERRORS + +expect object O { + fun hello(): MutableMap +} \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/classFunctionSameSignature/common/common.kt.after b/idea/testData/multiModuleQuickFix/classFunctionSameSignature/common/common.kt.after new file mode 100644 index 00000000000..fa6c82ec103 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/classFunctionSameSignature/common/common.kt.after @@ -0,0 +1,5 @@ +// DISABLE-ERRORS + +expect object O { + fun hello(): MutableMap +} \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/classFunctionSameSignature/jvm/jvm.kt b/idea/testData/multiModuleQuickFix/classFunctionSameSignature/jvm/jvm.kt new file mode 100644 index 00000000000..2a7096fdb81 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/classFunctionSameSignature/jvm/jvm.kt @@ -0,0 +1,8 @@ +// "Add missing actual members" "true" +// DISABLE-ERRORS + +actual object O { + fun hello(): MutableMap { + TODO("not implemented") + } +} \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/classFunctionSameSignature/jvm/jvm.kt.after b/idea/testData/multiModuleQuickFix/classFunctionSameSignature/jvm/jvm.kt.after new file mode 100644 index 00000000000..7236bd0d2d4 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/classFunctionSameSignature/jvm/jvm.kt.after @@ -0,0 +1,12 @@ +// "Add missing actual members" "true" +// DISABLE-ERRORS + +actual object O { + fun hello(): MutableMap { + TODO("not implemented") + } + + actual fun hello(): MutableMap { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiModuleTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiModuleTestGenerated.java index cb4e81c093b..86edca0edfb 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiModuleTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiModuleTestGenerated.java @@ -109,6 +109,11 @@ public class QuickFixMultiModuleTestGenerated extends AbstractQuickFixMultiModul runTest("idea/testData/multiModuleQuickFix/classFunction/"); } + @TestMetadata("classFunctionSameSignature") + public void testClassFunctionSameSignature() throws Exception { + runTest("idea/testData/multiModuleQuickFix/classFunctionSameSignature/"); + } + @TestMetadata("classFunctionWithConstructor") public void testClassFunctionWithConstructor() throws Exception { runTest("idea/testData/multiModuleQuickFix/classFunctionWithConstructor/");