Add actual: handle primary & secondary constructors as compatible
So #KT-23686 Fixed
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -219,19 +219,18 @@ internal fun KtPsiFactory.generateClassOrObjectByExpectedClass(
|
||||
actualNeeded: Boolean,
|
||||
existingDeclarations: List<KtDeclaration> = 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) ->
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// DISABLE-ERRORS
|
||||
|
||||
expect class My() {
|
||||
fun test()
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// DISABLE-ERRORS
|
||||
|
||||
expect class My() {
|
||||
fun test()
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// "Add missing actual members" "true"
|
||||
// DISABLE-ERRORS
|
||||
|
||||
actual class <caret>My {
|
||||
actual constructor()
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// "Add missing actual members" "true"
|
||||
// DISABLE-ERRORS
|
||||
|
||||
actual class My {
|
||||
actual constructor()
|
||||
|
||||
actual fun test() {}
|
||||
}
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
// DISABLE-ERRORS
|
||||
|
||||
expect class My(a: Int, b: String) {
|
||||
fun test()
|
||||
}
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
// DISABLE-ERRORS
|
||||
|
||||
expect class My(a: Int, b: String) {
|
||||
fun test()
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// "Add missing actual members" "true"
|
||||
// DISABLE-ERRORS
|
||||
|
||||
actual class <caret>My {
|
||||
actual constructor(a: Int, b: String)
|
||||
}
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
// "Add missing actual members" "true"
|
||||
// DISABLE-ERRORS
|
||||
|
||||
actual class My {
|
||||
actual constructor(a: Int, b: String)
|
||||
|
||||
actual fun test() {}
|
||||
}
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
// DISABLE-ERRORS
|
||||
|
||||
expect class My(a: Int, b: String) {
|
||||
fun test()
|
||||
|
||||
constructor(b: String, a: Int)
|
||||
}
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
// DISABLE-ERRORS
|
||||
|
||||
expect class My(a: Int, b: String) {
|
||||
fun test()
|
||||
|
||||
constructor(b: String, a: Int)
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// "Add missing actual members" "true"
|
||||
// DISABLE-ERRORS
|
||||
|
||||
actual class <caret>My {
|
||||
actual constructor(b: String, a: Int)
|
||||
}
|
||||
+8
@@ -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() {}
|
||||
}
|
||||
+15
@@ -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/");
|
||||
|
||||
Reference in New Issue
Block a user