Override/Implement: Do not generate bodies for header class members

#KT-15659 Fixed
This commit is contained in:
Alexey Sedunov
2017-08-15 17:32:50 +03:00
parent 6c3620f481
commit 6f8503a178
10 changed files with 39 additions and 14 deletions
@@ -119,7 +119,7 @@ class OverridesCompletion(
// keep original modifiers
val modifierList = KtPsiFactory(context.project).createModifierList(dummyMember.modifierList!!.text)
val prototype = memberObject.generateMember(context.project, false)
val prototype = memberObject.generateMember(classOrObject, false)
prototype.modifierList!!.replace(modifierList)
val insertedMember = dummyMember.replaced(prototype)
@@ -106,8 +106,7 @@ abstract class OverrideImplementMembersHandler : LanguageCodeInsightActionHandle
selectedElements: Collection<OverrideMemberChooserObject>,
copyDoc: Boolean
) {
val project = classOrObject.project
insertMembersAfter(editor, classOrObject, selectedElements.map { it.generateMember(project, copyDoc) })
insertMembersAfter(editor, classOrObject, selectedElements.map { it.generateMember(classOrObject, copyDoc) })
}
}
}
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.idea.j2k.IdeaDocCommentConverter
import org.jetbrains.kotlin.idea.kdoc.KDocElementFactory
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.util.approximateFlexibleTypes
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.findDocComment.findDocComment
import org.jetbrains.kotlin.renderer.*
@@ -95,7 +96,11 @@ interface OverrideMemberChooserObject : ClassMember {
}
}
fun OverrideMemberChooserObject.generateMember(project: Project, copyDoc: Boolean): KtCallableDeclaration {
fun OverrideMemberChooserObject.generateMember(targetClass: KtClassOrObject, copyDoc: Boolean): KtCallableDeclaration {
val project = targetClass.project
val bodyType = if (targetClass.hasModifier(KtTokens.HEADER_KEYWORD)) OverrideMemberChooserObject.BodyType.NO_BODY else bodyType
val descriptor = immediateSuper
if (preferConstructorParameter && descriptor is PropertyDescriptor) return generateConstructorParameter(project, descriptor)
@@ -164,7 +164,7 @@ class KotlinGenerateEqualsAndHashcodeAction : KotlinGenerateMemberActionBase<Kot
if (!needEquals) return null
val superEquals = classDescriptor.getSuperClassOrAny().findDeclaredEquals(true)!!
val equalsFun = generateFunctionSkeleton(superEquals, project)
val equalsFun = generateFunctionSkeleton(superEquals, targetClass)
val paramName = equalsFun.valueParameters.first().name!!.quoteIfNeeded()
var typeForCast = IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(classDescriptor)
@@ -249,7 +249,7 @@ class KotlinGenerateEqualsAndHashcodeAction : KotlinGenerateMemberActionBase<Kot
if (!needHashCode) return null
val superHashCode = classDescriptor.getSuperClassOrAny().findDeclaredHashCode(true)!!
val hashCodeFun = generateFunctionSkeleton(superHashCode, project)
val hashCodeFun = generateFunctionSkeleton(superHashCode, targetClass)
val builtins = superHashCode.builtIns
val propertyIterator = variablesForHashCode.iterator()
@@ -178,16 +178,16 @@ class KotlinGenerateToStringAction : KotlinGenerateMemberActionBase<KotlinGenera
project)
}
private fun generateToString(project: Project, info: Info): KtNamedFunction? {
private fun generateToString(targetClass: KtClassOrObject, info: Info): KtNamedFunction? {
val superToString = info.classDescriptor.getSuperClassOrAny().findDeclaredToString(true)!!
return generateFunctionSkeleton(superToString, project).apply {
bodyExpression!!.replace(KtPsiFactory(project).createExpression("{\n${info.generator.generate(info)}\n}"))
return generateFunctionSkeleton(superToString, targetClass).apply {
bodyExpression!!.replace(KtPsiFactory(targetClass).createExpression("{\n${info.generator.generate(info)}\n}"))
}
}
override fun generateMembers(project: Project, editor: Editor?, info: Info): List<KtDeclaration> {
val targetClass = info.classDescriptor.source.getPsi() as KtClass
val prototype = generateToString(project, info) ?: return emptyList()
val prototype = generateToString(targetClass, info) ?: return emptyList()
val anchor = with(targetClass.declarations) { lastIsInstanceOrNull<KtNamedFunction>() ?: lastOrNull() }
return insertMembersAfter(editor, targetClass, listOf(prototype), anchor)
}
@@ -79,8 +79,8 @@ fun confirmMemberRewrite(targetClass: KtClass, vararg descriptors: FunctionDescr
Messages.getQuestionIcon()) == Messages.YES
}
fun generateFunctionSkeleton(descriptor: FunctionDescriptor, project: Project): KtNamedFunction {
fun generateFunctionSkeleton(descriptor: FunctionDescriptor, targetClass: KtClassOrObject): KtNamedFunction {
return OverrideMemberChooserObject
.create(project, descriptor, descriptor, OverrideMemberChooserObject.BodyType.EMPTY)
.generateMember(project, false) as KtNamedFunction
.create(targetClass.project, descriptor, descriptor, OverrideMemberChooserObject.BodyType.EMPTY)
.generateMember(targetClass, false) as KtNamedFunction
}
@@ -82,7 +82,7 @@ class SpecifyOverrideExplicitlyFix(
project, delegatedDescriptor, overriddenDescriptor,
OverrideMemberChooserObject.BodyType.Delegate(delegateTargetDescriptor.name.asString())
)
val member = overrideMemberChooserObject.generateMember(project, copyDoc = false)
val member = overrideMemberChooserObject.generateMember(element, copyDoc = false)
val insertedMember = element.addDeclaration(member)
ShortenReferences.DEFAULT.process(insertedMember)
return
@@ -0,0 +1,8 @@
// "Implement members" "true"
// DISABLE-ERRORS
interface I {
fun foo()
}
header class <caret>Bar : I
@@ -0,0 +1,10 @@
// "Implement members" "true"
// DISABLE-ERRORS
interface I {
fun foo()
}
header class <caret>Bar : I {
override fun foo()
}
@@ -153,4 +153,7 @@ class QuickFixMultiModuleTest : AbstractQuickFixMultiModuleTest() {
@Test
fun testFunctionTypeReceiverToParameterByImpl() = doTestHeaderWithJvmAndJs()
@Test
fun testImplementMembersInHeaderClass() = doMultiPlatformTest(impls = *arrayOf())
}