Enable "add () fix" for expect base class without constructors

Related to KT-24597
This commit is contained in:
Mikhail Glukhikh
2018-08-06 13:54:04 +03:00
parent 79abf90916
commit a91442cd3b
5 changed files with 39 additions and 8 deletions
@@ -27,17 +27,21 @@ class AddDefaultConstructorFix(expectClass: KtClass) : KotlinQuickFixAction<KtCl
}
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>? {
val argumentList = diagnostic.psiElement as? KtValueArgumentList ?: return null
if (argumentList.arguments.isNotEmpty()) return null
val derivedClass = argumentList.getStrictParentOfType<KtClassOrObject>() ?: return null
val context = derivedClass.analyze()
val baseTypeCallEntry = derivedClass.superTypeListEntries.filterIsInstance<KtSuperTypeCallEntry>().firstOrNull() ?: return null
val baseType = context[BindingContext.TYPE, baseTypeCallEntry.typeReference] ?: 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
val baseClass = superTypeEntryToClass(baseTypeCallEntry, context) ?: return null
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.replaced
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.util.isExpectDeclaration
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.renderer.render
import org.jetbrains.kotlin.resolve.BindingContext
@@ -64,7 +64,9 @@ object SuperClassNotInitialized : KotlinIntentionActionsFactory() {
val constructors = superClass.constructors.filter {
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>()
@@ -122,7 +124,13 @@ object SuperClassNotInitialized : KotlinIntentionActionsFactory() {
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
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 + "()"))
if (baseClass != null && baseClass.hasExpectModifier() && baseClass.secondaryConstructors.isEmpty()) {
baseClass.createPrimaryConstructorIfAbsent()
}
if (putCaretIntoParenthesis) {
if (editor != null) {
@@ -0,0 +1,7 @@
// "Change to constructor invocation" "true"
// ENABLE_MULTIPLATFORM
// DISABLE-ERRORS
expect open class A
class B : A<caret>
@@ -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");
}
@TestMetadata("addParenthesisExpectClass.kt")
public void testAddParenthesisExpectClass() throws Exception {
runTest("idea/testData/quickfix/supertypeInitialization/addParenthesisExpectClass.kt");
}
@TestMetadata("addParenthesisForInvalidSealedClass.kt")
public void testAddParenthesisForInvalidSealedClass() throws Exception {
runTest("idea/testData/quickfix/supertypeInitialization/addParenthesisForInvalidSealedClass.kt");