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 expectedClass = expectedClassPointer.element ?: return
|
||||||
val factory = KtPsiFactory(element)
|
val factory = KtPsiFactory(element)
|
||||||
val pureActualClass = factory.generateClassOrObjectByExpectedClass(
|
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) {
|
for (declaration in pureActualClass.declarations) {
|
||||||
element.addDeclaration(declaration)
|
element.addDeclaration(declaration)
|
||||||
|
|||||||
@@ -219,19 +219,18 @@ internal fun KtPsiFactory.generateClassOrObjectByExpectedClass(
|
|||||||
actualNeeded: Boolean,
|
actualNeeded: Boolean,
|
||||||
existingDeclarations: List<KtDeclaration> = emptyList()
|
existingDeclarations: List<KtDeclaration> = emptyList()
|
||||||
): KtClassOrObject {
|
): 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() =
|
fun KtDeclaration.exists() =
|
||||||
existingDeclarations.any {
|
existingDeclarations.any {
|
||||||
name == it.name && this.javaClass == it.javaClass && when (this) {
|
name == it.name && when (this) {
|
||||||
is KtClassOrObject, is KtProperty, is KtEnumEntry -> true
|
is KtConstructor<*> -> it is KtConstructor<*> && areCompatible(this, it)
|
||||||
is KtFunction -> {
|
is KtNamedFunction -> it is KtNamedFunction && areCompatible(this, it)
|
||||||
it as KtFunction
|
else -> this.javaClass == it.javaClass
|
||||||
valueParameters.size == it.valueParameters.size &&
|
|
||||||
valueParameters.zip(it.valueParameters).all { (parameter, existingParameter) ->
|
|
||||||
parameter.name == existingParameter.name &&
|
|
||||||
parameter.typeReference?.text == existingParameter.typeReference?.text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,6 +265,10 @@ internal fun KtPsiFactory.generateClassOrObjectByExpectedClass(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
val primaryConstructor = actualClass.primaryConstructor
|
||||||
|
if (primaryConstructor != null && primaryConstructor.exists()) {
|
||||||
|
primaryConstructor.delete()
|
||||||
|
}
|
||||||
|
|
||||||
val context = expectedClass.analyze()
|
val context = expectedClass.analyze()
|
||||||
actualClass.superTypeListEntries.zip(expectedClass.superTypeListEntries).forEach { (actualEntry, expectedEntry) ->
|
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/");
|
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")
|
@TestMetadata("classOverloadedFunction")
|
||||||
public void testClassOverloadedFunction() throws Exception {
|
public void testClassOverloadedFunction() throws Exception {
|
||||||
runTest("idea/testData/multiModuleQuickFix/classOverloadedFunction/");
|
runTest("idea/testData/multiModuleQuickFix/classOverloadedFunction/");
|
||||||
|
|||||||
Reference in New Issue
Block a user