Implement Members Quick-Fix: Support primary constructor parameters
#KT-8427 In Progress
This commit is contained in:
+2
-2
@@ -60,7 +60,7 @@ class OverridesCompletion(
|
||||
|
||||
val classOrObject = position.getNonStrictParentOfType<KtClassOrObject>() ?: return
|
||||
|
||||
val members = OverrideMembersHandler().collectMembersToGenerate(classOrObject)
|
||||
val members = OverrideMembersHandler(isConstructorParameter).collectMembersToGenerate(classOrObject)
|
||||
|
||||
for (memberObject in members) {
|
||||
if (isConstructorParameter && memberObject.descriptor !is PropertyDescriptor) continue
|
||||
@@ -114,7 +114,7 @@ class OverridesCompletion(
|
||||
// keep original modifiers
|
||||
val modifierList = KtPsiFactory(context.project).createModifierList(dummyMember.modifierList!!.text)
|
||||
|
||||
val prototype = memberObject.generateMember(context.project, isConstructorParameter)
|
||||
val prototype = memberObject.generateMember(context.project)
|
||||
prototype.modifierList!!.replace(modifierList)
|
||||
val insertedMember = dummyMember.replaced(prototype)
|
||||
|
||||
|
||||
+22
-1
@@ -21,10 +21,15 @@ import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiFile
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.idea.KotlinBundle
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||
import org.jetbrains.kotlin.psi.KtClass
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtEnumEntry
|
||||
import org.jetbrains.kotlin.resolve.OverrideResolver
|
||||
|
||||
public class ImplementMembersHandler : OverrideImplementMembersHandler(), IntentionAction {
|
||||
public open class ImplementMembersHandler : OverrideImplementMembersHandler(), IntentionAction {
|
||||
override fun collectMembersToGenerate(descriptor: ClassDescriptor, project: Project): Collection<OverrideMemberChooserObject> {
|
||||
return OverrideResolver.getMissingImplementations(descriptor)
|
||||
.map { OverrideMemberChooserObject.create(project, it, it, OverrideMemberChooserObject.BodyType.EMPTY) }
|
||||
@@ -39,3 +44,19 @@ public class ImplementMembersHandler : OverrideImplementMembersHandler(), Intent
|
||||
|
||||
override fun isAvailable(project: Project, editor: Editor, file: PsiFile) = isValidFor(editor, file)
|
||||
}
|
||||
|
||||
public class ImplementAsConstructorParameter : ImplementMembersHandler() {
|
||||
override fun getText() = "Implement as constructor parameters"
|
||||
|
||||
override fun isValidForClass(classOrObject: KtClassOrObject): Boolean {
|
||||
if (classOrObject !is KtClass || classOrObject is KtEnumEntry || classOrObject.isInterface()) return false
|
||||
val classDescriptor = classOrObject.resolveToDescriptorIfAny() as? ClassDescriptor ?: return false
|
||||
return OverrideResolver.getMissingImplementations(classDescriptor).any { it is PropertyDescriptor }
|
||||
}
|
||||
|
||||
override fun collectMembersToGenerate(descriptor: ClassDescriptor, project: Project): Collection<OverrideMemberChooserObject> {
|
||||
return OverrideResolver.getMissingImplementations(descriptor)
|
||||
.filter { it is PropertyDescriptor }
|
||||
.map { OverrideMemberChooserObject.create(project, it, it, OverrideMemberChooserObject.BodyType.EMPTY, true) }
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -51,11 +51,13 @@ public abstract class OverrideImplementMembersHandler : LanguageCodeInsightActio
|
||||
|
||||
protected abstract fun getChooserTitle(): String
|
||||
|
||||
protected open fun isValidForClass(classOrObject: KtClassOrObject) = true
|
||||
|
||||
override fun isValidFor(editor: Editor, file: PsiFile): Boolean {
|
||||
if (file !is KtFile) return false
|
||||
val elementAtCaret = file.findElementAt(editor.caretModel.offset)
|
||||
val classOrObject = elementAtCaret?.getNonStrictParentOfType<KtClassOrObject>()
|
||||
return classOrObject != null
|
||||
return classOrObject != null && isValidForClass(classOrObject)
|
||||
}
|
||||
|
||||
protected abstract fun getNoMembersFoundHint(): String
|
||||
|
||||
+15
-10
@@ -39,15 +39,21 @@ interface OverrideMemberChooserObject : ClassMember {
|
||||
val descriptor: CallableMemberDescriptor
|
||||
val immediateSuper: CallableMemberDescriptor
|
||||
val bodyType: BodyType
|
||||
val preferConstructorParameter: Boolean
|
||||
|
||||
companion object {
|
||||
fun create(project: Project, descriptor: CallableMemberDescriptor, immediateSuper: CallableMemberDescriptor, bodyType: BodyType): OverrideMemberChooserObject {
|
||||
fun create(project: Project,
|
||||
descriptor: CallableMemberDescriptor,
|
||||
immediateSuper: CallableMemberDescriptor,
|
||||
bodyType: BodyType,
|
||||
preferConstructorParameter: Boolean = false
|
||||
): OverrideMemberChooserObject {
|
||||
val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, descriptor)
|
||||
if (declaration != null) {
|
||||
return WithDeclaration(descriptor, declaration, immediateSuper, bodyType)
|
||||
return WithDeclaration(descriptor, declaration, immediateSuper, bodyType, preferConstructorParameter)
|
||||
}
|
||||
else {
|
||||
return WithoutDeclaration(descriptor, immediateSuper, bodyType)
|
||||
return WithoutDeclaration(descriptor, immediateSuper, bodyType, preferConstructorParameter)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +61,8 @@ interface OverrideMemberChooserObject : ClassMember {
|
||||
descriptor: CallableMemberDescriptor,
|
||||
declaration: PsiElement,
|
||||
override val immediateSuper: CallableMemberDescriptor,
|
||||
override val bodyType: BodyType
|
||||
override val bodyType: BodyType,
|
||||
override val preferConstructorParameter: Boolean
|
||||
) : DescriptorMemberChooserObject(declaration, descriptor), OverrideMemberChooserObject {
|
||||
|
||||
override val descriptor: CallableMemberDescriptor
|
||||
@@ -65,7 +72,8 @@ interface OverrideMemberChooserObject : ClassMember {
|
||||
private class WithoutDeclaration(
|
||||
override val descriptor: CallableMemberDescriptor,
|
||||
override val immediateSuper: CallableMemberDescriptor,
|
||||
override val bodyType: BodyType
|
||||
override val bodyType: BodyType,
|
||||
override val preferConstructorParameter: Boolean
|
||||
) : MemberChooserObjectBase(DescriptorMemberChooserObject.getText(descriptor), DescriptorMemberChooserObject.getIcon(null, descriptor)), OverrideMemberChooserObject {
|
||||
|
||||
override fun getParentNodeDelegate(): MemberChooserObject? {
|
||||
@@ -76,12 +84,9 @@ interface OverrideMemberChooserObject : ClassMember {
|
||||
}
|
||||
}
|
||||
|
||||
fun OverrideMemberChooserObject.generateMember(project: Project, asConstructorParameter: Boolean = false): KtCallableDeclaration {
|
||||
fun OverrideMemberChooserObject.generateMember(project: Project): KtCallableDeclaration {
|
||||
val descriptor = immediateSuper
|
||||
if (asConstructorParameter) {
|
||||
assert(descriptor is PropertyDescriptor) { "asConstructorParameter is valid only for PropertyDescriptor" }
|
||||
return generateConstructorParameter(project, descriptor as PropertyDescriptor)
|
||||
}
|
||||
if (preferConstructorParameter && descriptor is PropertyDescriptor) return generateConstructorParameter(project, descriptor)
|
||||
|
||||
return when (descriptor) {
|
||||
is SimpleFunctionDescriptor -> generateFunction(project, descriptor, bodyType)
|
||||
|
||||
+2
-2
@@ -23,7 +23,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import java.util.*
|
||||
|
||||
public class OverrideMembersHandler : OverrideImplementMembersHandler() {
|
||||
public class OverrideMembersHandler(private val preferConstructorParameters: Boolean = false) : OverrideImplementMembersHandler() {
|
||||
override fun collectMembersToGenerate(descriptor: ClassDescriptor, project: Project): Collection<OverrideMemberChooserObject> {
|
||||
val result = ArrayList<OverrideMemberChooserObject>()
|
||||
for (member in descriptor.unsubstitutedMemberScope.getContributedDescriptors()) {
|
||||
@@ -73,7 +73,7 @@ public class OverrideMembersHandler : OverrideImplementMembersHandler() {
|
||||
else
|
||||
OverrideMemberChooserObject.BodyType.QUALIFIED_SUPER
|
||||
|
||||
result.add(OverrideMemberChooserObject.create(project, realSuper, immediateSuperToUse, bodyType))
|
||||
result.add(OverrideMemberChooserObject.create(project, realSuper, immediateSuperToUse, bodyType, preferConstructorParameters))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.idea.quickfix
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
|
||||
import org.jetbrains.kotlin.diagnostics.Errors.*
|
||||
import org.jetbrains.kotlin.idea.core.overrideImplement.ImplementAsConstructorParameter
|
||||
import org.jetbrains.kotlin.idea.core.overrideImplement.ImplementMembersHandler
|
||||
import org.jetbrains.kotlin.idea.inspections.AddModifierFixFactory
|
||||
import org.jetbrains.kotlin.idea.inspections.AddReflectionQuickFix
|
||||
@@ -156,10 +157,11 @@ public class QuickFixRegistrar : QuickFixContributor {
|
||||
USELESS_NULLABLE_CHECK.registerFactory(RemoveNullableFix.createFactory(RemoveNullableFix.NullableKind.USELESS))
|
||||
|
||||
|
||||
val implementMethodsHandler = ImplementMembersHandler()
|
||||
ABSTRACT_MEMBER_NOT_IMPLEMENTED.registerActions(implementMethodsHandler)
|
||||
ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED.registerActions(implementMethodsHandler)
|
||||
MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED.registerActions(implementMethodsHandler)
|
||||
val implementMembersHandler = ImplementMembersHandler()
|
||||
val implementMembersAsParametersHandler = ImplementAsConstructorParameter()
|
||||
ABSTRACT_MEMBER_NOT_IMPLEMENTED.registerActions(implementMembersHandler, implementMembersAsParametersHandler)
|
||||
ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED.registerActions(implementMembersHandler, implementMembersAsParametersHandler)
|
||||
MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED.registerActions(implementMembersHandler, implementMembersAsParametersHandler)
|
||||
|
||||
VAL_WITH_SETTER.registerFactory(ChangeVariableMutabilityFix.VAL_WITH_SETTER_FACTORY)
|
||||
VAL_REASSIGNMENT.registerFactory(ChangeVariableMutabilityFix.VAL_REASSIGNMENT_FACTORY)
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
// "Implement as constructor parameters" "true"
|
||||
interface I {
|
||||
val foo: Int
|
||||
}
|
||||
|
||||
<caret>class A : I
|
||||
@@ -0,0 +1,6 @@
|
||||
// "Implement as constructor parameters" "true"
|
||||
interface I {
|
||||
val foo: Int
|
||||
}
|
||||
|
||||
<caret>class A(override val foo: Int) : I
|
||||
@@ -0,0 +1,13 @@
|
||||
// "Implement as constructor parameters" "false"
|
||||
// ACTION: Create test
|
||||
// ACTION: Implement members
|
||||
// ACTION: Make 'A' abstract
|
||||
// ACTION: Make internal
|
||||
// ACTION: Make private
|
||||
// ACTION: Move 'A' to separate file
|
||||
// ERROR: Class 'A' must be declared abstract or implement abstract member public abstract fun foo(): kotlin.Int defined in I
|
||||
interface I {
|
||||
fun foo(): Int
|
||||
}
|
||||
|
||||
<caret>class A : I
|
||||
@@ -0,0 +1,12 @@
|
||||
// "Implement as constructor parameters" "false"
|
||||
// ACTION: Create test
|
||||
// ACTION: Implement members
|
||||
// ACTION: Make internal
|
||||
// ACTION: Make private
|
||||
// ACTION: Move 'A' to separate file
|
||||
// ERROR: Object 'A' must be declared abstract or implement abstract member public abstract val foo: kotlin.Int defined in I
|
||||
interface I {
|
||||
val foo: Int
|
||||
}
|
||||
|
||||
<caret>object A : I
|
||||
@@ -5364,6 +5364,24 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("implemenAsConstructorParameter.kt")
|
||||
public void testImplemenAsConstructorParameter() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/override/implemenAsConstructorParameter.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("implemenAsConstructorParameterFunction.kt")
|
||||
public void testImplemenAsConstructorParameterFunction() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/override/implemenAsConstructorParameterFunction.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("implemenAsConstructorParameterInObject.kt")
|
||||
public void testImplemenAsConstructorParameterInObject() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/override/implemenAsConstructorParameterInObject.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("implementMember.kt")
|
||||
public void testImplementMember() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/override/implementMember.kt");
|
||||
|
||||
Reference in New Issue
Block a user