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 f8ec5366bc4..842d2dc9eee 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/AddActualFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/AddActualFix.kt @@ -47,7 +47,8 @@ class AddActualFix( val expectedClass = expectedClassPointer.element ?: return val factory = KtPsiFactory(element) val pureActualClass = factory.generateClassOrObjectByExpectedClass( - project, expectedClass, actualNeeded = true, existingDeclarations = element.declarations + project, expectedClass, actualNeeded = true, + existingDeclarations = element.declarations + listOfNotNull(element.primaryConstructor) ) for (declaration in pureActualClass.declarations) { element.addDeclaration(declaration) 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 60706308191..1eade559279 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/CreateActualFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/expectactual/CreateActualFix.kt @@ -219,19 +219,18 @@ internal fun KtPsiFactory.generateClassOrObjectByExpectedClass( actualNeeded: Boolean, existingDeclarations: List = emptyList() ): KtClassOrObject { + fun areCompatible(first: KtFunction, second: KtFunction) = + first.valueParameters.size == second.valueParameters.size && + first.valueParameters.zip(second.valueParameters).all { (firstParam, secondParam) -> + firstParam.name == secondParam.name && firstParam.typeReference?.text == secondParam.typeReference?.text + } + fun KtDeclaration.exists() = existingDeclarations.any { - name == it.name && this.javaClass == it.javaClass && when (this) { - is KtClassOrObject, is KtProperty, is KtEnumEntry -> true - is KtFunction -> { - it as KtFunction - valueParameters.size == it.valueParameters.size && - valueParameters.zip(it.valueParameters).all { (parameter, existingParameter) -> - parameter.name == existingParameter.name && - parameter.typeReference?.text == existingParameter.typeReference?.text - } - } - else -> true + name == it.name && when (this) { + is KtConstructor<*> -> it is KtConstructor<*> && areCompatible(this, it) + is KtNamedFunction -> it is KtNamedFunction && areCompatible(this, it) + else -> this.javaClass == it.javaClass } } @@ -266,6 +265,10 @@ internal fun KtPsiFactory.generateClassOrObjectByExpectedClass( } } } + val primaryConstructor = actualClass.primaryConstructor + if (primaryConstructor != null && primaryConstructor.exists()) { + primaryConstructor.delete() + } val context = expectedClass.analyze() actualClass.superTypeListEntries.zip(expectedClass.superTypeListEntries).forEach { (actualEntry, expectedEntry) -> diff --git a/idea/testData/multiModuleQuickFix/classFunctionWithConstructor/header/header.kt b/idea/testData/multiModuleQuickFix/classFunctionWithConstructor/header/header.kt new file mode 100644 index 00000000000..fd136e08278 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/classFunctionWithConstructor/header/header.kt @@ -0,0 +1,5 @@ +// DISABLE-ERRORS + +expect class My() { + fun test() +} \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/classFunctionWithConstructor/header/header.kt.after b/idea/testData/multiModuleQuickFix/classFunctionWithConstructor/header/header.kt.after new file mode 100644 index 00000000000..fd136e08278 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/classFunctionWithConstructor/header/header.kt.after @@ -0,0 +1,5 @@ +// DISABLE-ERRORS + +expect class My() { + fun test() +} \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/classFunctionWithConstructor/jvm/My.kt b/idea/testData/multiModuleQuickFix/classFunctionWithConstructor/jvm/My.kt new file mode 100644 index 00000000000..2484300d1a5 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/classFunctionWithConstructor/jvm/My.kt @@ -0,0 +1,6 @@ +// "Add missing actual members" "true" +// DISABLE-ERRORS + +actual class My { + actual constructor() +} diff --git a/idea/testData/multiModuleQuickFix/classFunctionWithConstructor/jvm/My.kt.after b/idea/testData/multiModuleQuickFix/classFunctionWithConstructor/jvm/My.kt.after new file mode 100644 index 00000000000..0da3244bf86 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/classFunctionWithConstructor/jvm/My.kt.after @@ -0,0 +1,8 @@ +// "Add missing actual members" "true" +// DISABLE-ERRORS + +actual class My { + actual constructor() + + actual fun test() {} +} diff --git a/idea/testData/multiModuleQuickFix/classFunctionWithConstructorAndParameters/header/header.kt b/idea/testData/multiModuleQuickFix/classFunctionWithConstructorAndParameters/header/header.kt new file mode 100644 index 00000000000..96c0726b5f3 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/classFunctionWithConstructorAndParameters/header/header.kt @@ -0,0 +1,5 @@ +// DISABLE-ERRORS + +expect class My(a: Int, b: String) { + fun test() +} \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/classFunctionWithConstructorAndParameters/header/header.kt.after b/idea/testData/multiModuleQuickFix/classFunctionWithConstructorAndParameters/header/header.kt.after new file mode 100644 index 00000000000..96c0726b5f3 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/classFunctionWithConstructorAndParameters/header/header.kt.after @@ -0,0 +1,5 @@ +// DISABLE-ERRORS + +expect class My(a: Int, b: String) { + fun test() +} \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/classFunctionWithConstructorAndParameters/jvm/My.kt b/idea/testData/multiModuleQuickFix/classFunctionWithConstructorAndParameters/jvm/My.kt new file mode 100644 index 00000000000..94d423c7d53 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/classFunctionWithConstructorAndParameters/jvm/My.kt @@ -0,0 +1,6 @@ +// "Add missing actual members" "true" +// DISABLE-ERRORS + +actual class My { + actual constructor(a: Int, b: String) +} diff --git a/idea/testData/multiModuleQuickFix/classFunctionWithConstructorAndParameters/jvm/My.kt.after b/idea/testData/multiModuleQuickFix/classFunctionWithConstructorAndParameters/jvm/My.kt.after new file mode 100644 index 00000000000..aea56139b3c --- /dev/null +++ b/idea/testData/multiModuleQuickFix/classFunctionWithConstructorAndParameters/jvm/My.kt.after @@ -0,0 +1,8 @@ +// "Add missing actual members" "true" +// DISABLE-ERRORS + +actual class My { + actual constructor(a: Int, b: String) + + actual fun test() {} +} diff --git a/idea/testData/multiModuleQuickFix/classFunctionWithIncompatibleConstructor/header/header.kt b/idea/testData/multiModuleQuickFix/classFunctionWithIncompatibleConstructor/header/header.kt new file mode 100644 index 00000000000..b9bec41c7ec --- /dev/null +++ b/idea/testData/multiModuleQuickFix/classFunctionWithIncompatibleConstructor/header/header.kt @@ -0,0 +1,7 @@ +// DISABLE-ERRORS + +expect class My(a: Int, b: String) { + fun test() + + constructor(b: String, a: Int) +} \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/classFunctionWithIncompatibleConstructor/header/header.kt.after b/idea/testData/multiModuleQuickFix/classFunctionWithIncompatibleConstructor/header/header.kt.after new file mode 100644 index 00000000000..b9bec41c7ec --- /dev/null +++ b/idea/testData/multiModuleQuickFix/classFunctionWithIncompatibleConstructor/header/header.kt.after @@ -0,0 +1,7 @@ +// DISABLE-ERRORS + +expect class My(a: Int, b: String) { + fun test() + + constructor(b: String, a: Int) +} \ No newline at end of file diff --git a/idea/testData/multiModuleQuickFix/classFunctionWithIncompatibleConstructor/jvm/My.kt b/idea/testData/multiModuleQuickFix/classFunctionWithIncompatibleConstructor/jvm/My.kt new file mode 100644 index 00000000000..b918c29fb13 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/classFunctionWithIncompatibleConstructor/jvm/My.kt @@ -0,0 +1,6 @@ +// "Add missing actual members" "true" +// DISABLE-ERRORS + +actual class My { + actual constructor(b: String, a: Int) +} diff --git a/idea/testData/multiModuleQuickFix/classFunctionWithIncompatibleConstructor/jvm/My.kt.after b/idea/testData/multiModuleQuickFix/classFunctionWithIncompatibleConstructor/jvm/My.kt.after new file mode 100644 index 00000000000..8e2608fa708 --- /dev/null +++ b/idea/testData/multiModuleQuickFix/classFunctionWithIncompatibleConstructor/jvm/My.kt.after @@ -0,0 +1,8 @@ +// "Add missing actual members" "true" +// DISABLE-ERRORS + +actual class My actual constructor(a: Int, b: String) { + actual constructor(b: String, a: Int) + + actual fun test() {} +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiModuleTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiModuleTestGenerated.java index 8b179e36000..2377f495aab 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiModuleTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiModuleTestGenerated.java @@ -79,6 +79,21 @@ public class QuickFixMultiModuleTestGenerated extends AbstractQuickFixMultiModul runTest("idea/testData/multiModuleQuickFix/classFunction/"); } + @TestMetadata("classFunctionWithConstructor") + public void testClassFunctionWithConstructor() throws Exception { + runTest("idea/testData/multiModuleQuickFix/classFunctionWithConstructor/"); + } + + @TestMetadata("classFunctionWithConstructorAndParameters") + public void testClassFunctionWithConstructorAndParameters() throws Exception { + runTest("idea/testData/multiModuleQuickFix/classFunctionWithConstructorAndParameters/"); + } + + @TestMetadata("classFunctionWithIncompatibleConstructor") + public void testClassFunctionWithIncompatibleConstructor() throws Exception { + runTest("idea/testData/multiModuleQuickFix/classFunctionWithIncompatibleConstructor/"); + } + @TestMetadata("classOverloadedFunction") public void testClassOverloadedFunction() throws Exception { runTest("idea/testData/multiModuleQuickFix/classOverloadedFunction/");