Enable "add () fix" for expect base class without constructors
Related to KT-24597
This commit is contained in:
@@ -27,17 +27,21 @@ class AddDefaultConstructorFix(expectClass: KtClass) : KotlinQuickFixAction<KtCl
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object : KotlinSingleIntentionActionFactory() {
|
companion object : KotlinSingleIntentionActionFactory() {
|
||||||
|
fun superTypeEntryToClass(typeEntry: KtSuperTypeListEntry, context: BindingContext): KtClass? {
|
||||||
|
val baseType = context[BindingContext.TYPE, typeEntry.typeReference] ?: return null
|
||||||
|
val baseClassDescriptor = baseType.constructor.declarationDescriptor as? ClassDescriptor ?: return null
|
||||||
|
if (!baseClassDescriptor.isExpect) return null
|
||||||
|
if (baseClassDescriptor.kind != ClassKind.CLASS) return null
|
||||||
|
return DescriptorToSourceUtils.descriptorToDeclaration(baseClassDescriptor) as? KtClass
|
||||||
|
}
|
||||||
|
|
||||||
override fun createAction(diagnostic: Diagnostic): KotlinQuickFixAction<KtClass>? {
|
override fun createAction(diagnostic: Diagnostic): KotlinQuickFixAction<KtClass>? {
|
||||||
val argumentList = diagnostic.psiElement as? KtValueArgumentList ?: return null
|
val argumentList = diagnostic.psiElement as? KtValueArgumentList ?: return null
|
||||||
if (argumentList.arguments.isNotEmpty()) return null
|
if (argumentList.arguments.isNotEmpty()) return null
|
||||||
val derivedClass = argumentList.getStrictParentOfType<KtClassOrObject>() ?: return null
|
val derivedClass = argumentList.getStrictParentOfType<KtClassOrObject>() ?: return null
|
||||||
val context = derivedClass.analyze()
|
val context = derivedClass.analyze()
|
||||||
val baseTypeCallEntry = derivedClass.superTypeListEntries.filterIsInstance<KtSuperTypeCallEntry>().firstOrNull() ?: return null
|
val baseTypeCallEntry = derivedClass.superTypeListEntries.filterIsInstance<KtSuperTypeCallEntry>().firstOrNull() ?: return null
|
||||||
val baseType = context[BindingContext.TYPE, baseTypeCallEntry.typeReference] ?: return null
|
val baseClass = superTypeEntryToClass(baseTypeCallEntry, context) ?: return null
|
||||||
val baseClassDescriptor = baseType.constructor.declarationDescriptor as? ClassDescriptor ?: return null
|
|
||||||
if (!baseClassDescriptor.isExpect) return null
|
|
||||||
if (baseClassDescriptor.kind != ClassKind.CLASS) return null
|
|
||||||
val baseClass = DescriptorToSourceUtils.descriptorToDeclaration(baseClassDescriptor) as? KtClass ?: return null
|
|
||||||
return AddDefaultConstructorFix(baseClass)
|
return AddDefaultConstructorFix(baseClass)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,9 +32,9 @@ import org.jetbrains.kotlin.idea.core.isVisible
|
|||||||
import org.jetbrains.kotlin.idea.core.moveCaret
|
import org.jetbrains.kotlin.idea.core.moveCaret
|
||||||
import org.jetbrains.kotlin.idea.core.replaced
|
import org.jetbrains.kotlin.idea.core.replaced
|
||||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||||
|
import org.jetbrains.kotlin.idea.util.isExpectDeclaration
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
|
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
|
||||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||||
import org.jetbrains.kotlin.renderer.render
|
import org.jetbrains.kotlin.renderer.render
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
@@ -64,7 +64,9 @@ object SuperClassNotInitialized : KotlinIntentionActionsFactory() {
|
|||||||
val constructors = superClass.constructors.filter {
|
val constructors = superClass.constructors.filter {
|
||||||
it.isVisible(classDescriptor) || (superClass.modality == Modality.SEALED && inSameFile)
|
it.isVisible(classDescriptor) || (superClass.modality == Modality.SEALED && inSameFile)
|
||||||
}
|
}
|
||||||
if (constructors.isEmpty()) return emptyList() // no accessible constructor
|
if (constructors.isEmpty() && (!superClass.isExpect || superClass.kind != ClassKind.CLASS)) {
|
||||||
|
return emptyList() // no accessible constructor
|
||||||
|
}
|
||||||
|
|
||||||
val fixes = ArrayList<IntentionAction>()
|
val fixes = ArrayList<IntentionAction>()
|
||||||
|
|
||||||
@@ -122,7 +124,13 @@ object SuperClassNotInitialized : KotlinIntentionActionsFactory() {
|
|||||||
|
|
||||||
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
|
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
|
||||||
val element = element ?: return
|
val element = element ?: return
|
||||||
|
val context = (element.getStrictParentOfType<KtClassOrObject>() ?: element).analyze()
|
||||||
|
val baseClass = AddDefaultConstructorFix.superTypeEntryToClass(element, context)
|
||||||
|
|
||||||
val newSpecifier = element.replaced(KtPsiFactory(project).createSuperTypeCallEntry(element.text + "()"))
|
val newSpecifier = element.replaced(KtPsiFactory(project).createSuperTypeCallEntry(element.text + "()"))
|
||||||
|
if (baseClass != null && baseClass.hasExpectModifier() && baseClass.secondaryConstructors.isEmpty()) {
|
||||||
|
baseClass.createPrimaryConstructorIfAbsent()
|
||||||
|
}
|
||||||
|
|
||||||
if (putCaretIntoParenthesis) {
|
if (putCaretIntoParenthesis) {
|
||||||
if (editor != null) {
|
if (editor != null) {
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
// "Change to constructor invocation" "true"
|
||||||
|
// ENABLE_MULTIPLATFORM
|
||||||
|
// DISABLE-ERRORS
|
||||||
|
|
||||||
|
expect open class A
|
||||||
|
|
||||||
|
class B : A<caret>
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
// "Change to constructor invocation" "true"
|
||||||
|
// ENABLE_MULTIPLATFORM
|
||||||
|
// DISABLE-ERRORS
|
||||||
|
|
||||||
|
expect open class A()
|
||||||
|
|
||||||
|
class B : A(<caret>)
|
||||||
@@ -10026,6 +10026,11 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
|||||||
runTest("idea/testData/quickfix/supertypeInitialization/addParenthesisEmptyConstructor.kt");
|
runTest("idea/testData/quickfix/supertypeInitialization/addParenthesisEmptyConstructor.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("addParenthesisExpectClass.kt")
|
||||||
|
public void testAddParenthesisExpectClass() throws Exception {
|
||||||
|
runTest("idea/testData/quickfix/supertypeInitialization/addParenthesisExpectClass.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("addParenthesisForInvalidSealedClass.kt")
|
@TestMetadata("addParenthesisForInvalidSealedClass.kt")
|
||||||
public void testAddParenthesisForInvalidSealedClass() throws Exception {
|
public void testAddParenthesisForInvalidSealedClass() throws Exception {
|
||||||
runTest("idea/testData/quickfix/supertypeInitialization/addParenthesisForInvalidSealedClass.kt");
|
runTest("idea/testData/quickfix/supertypeInitialization/addParenthesisForInvalidSealedClass.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user