Initial implementation of KT-5955 Completion for override methods

#KT-5955 Fixed
This commit is contained in:
Valentin Kipyatkov
2015-09-24 12:33:59 +03:00
parent 15edbbb60c
commit 1c6ca9d036
31 changed files with 599 additions and 117 deletions
@@ -23,18 +23,18 @@ import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.DialogWrapper
import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.*
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiWhiteSpace
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.quickfix.moveCaretIntoGeneratedElement
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.util.ShortenReferences
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.renderer.*
import java.util.*
public abstract class OverrideImplementMembersHandler : LanguageCodeInsightActionHandler {
@@ -86,7 +86,7 @@ public abstract class OverrideImplementMembersHandler : LanguageCodeInsightActio
PsiDocumentManager.getInstance(project).commitAllDocuments()
generateMethods(editor, classOrObject, selectedElements)
generateMembers(editor, classOrObject, selectedElements)
}
override fun invoke(project: Project, editor: Editor, file: PsiFile) = invoke(project, editor, file, false)
@@ -94,50 +94,33 @@ public abstract class OverrideImplementMembersHandler : LanguageCodeInsightActio
override fun startInWriteAction(): Boolean = false
companion object {
private val OVERRIDE_RENDERER = DescriptorRenderer.withOptions {
renderDefaultValues = false
modifiers = setOf(DescriptorRendererModifier.OVERRIDE)
withDefinedIn = false
nameShortness = NameShortness.SOURCE_CODE_QUALIFIED
overrideRenderingPolicy = OverrideRenderingPolicy.RENDER_OVERRIDE
unitReturnType = false
typeNormalizer = IdeDescriptorRenderers.APPROXIMATE_FLEXIBLE_TYPES
}
public fun generateMethods(editor: Editor, classOrObject: JetClassOrObject, selectedElements: Collection<OverrideMemberChooserObject>) {
public fun generateMembers(editor: Editor, classOrObject: JetClassOrObject, selectedElements: Collection<OverrideMemberChooserObject>) {
runWriteAction {
if (selectedElements.isEmpty()) return@runWriteAction
val body = classOrObject.getOrCreateBody()
var afterAnchor = findInsertAfterAnchor(editor, body) ?: return@runWriteAction
var firstGenerated: PsiElement? = null
val elementsToCompact = ArrayList<JetElement>()
for (element in generateOverridingMembers(selectedElements, classOrObject)) {
val added = body.addAfter(element, afterAnchor)
val project = classOrObject.project
val insertedMembers = ArrayList<JetCallableDeclaration>()
for (memberObject in selectedElements) {
val member = memberObject.generateMember(project)
val added = body.addAfter(member, afterAnchor) as JetCallableDeclaration
if (firstGenerated == null) {
firstGenerated = added
}
afterAnchor = added
elementsToCompact.add(added as JetElement)
insertedMembers.add(added)
}
ShortenReferences.Companion.DEFAULT.process(elementsToCompact)
if (firstGenerated == null) return@runWriteAction
val project = classOrObject.project
val pointer = SmartPointerManager.getInstance(project).createSmartPsiElementPointer(firstGenerated)
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.document)
val element = pointer.element
if (element != null) {
moveCaretIntoGeneratedElement(editor, element)
}
ShortenReferences.DEFAULT.process(insertedMembers)
moveCaretIntoGeneratedElement(editor, firstGenerated!!)
}
}
@@ -182,76 +165,5 @@ public abstract class OverrideImplementMembersHandler : LanguageCodeInsightActio
return whiteSpace
}
private fun generateOverridingMembers(selectedElements: Collection<OverrideMemberChooserObject>,
classOrObject: JetClassOrObject): List<JetElement> {
val overridingMembers = ArrayList<JetElement>()
for (selectedElement in selectedElements) {
val descriptor = selectedElement.immediateSuper
when (descriptor) {
is SimpleFunctionDescriptor -> overridingMembers.add(overrideFunction(classOrObject, descriptor, selectedElement.bodyType))
is PropertyDescriptor -> overridingMembers.add(overrideProperty(classOrObject, descriptor, selectedElement.bodyType))
else -> error("Unknown member to override: $descriptor")
}
}
return overridingMembers
}
private fun overrideProperty(classOrObject: JetClassOrObject, descriptor: PropertyDescriptor, bodyType: OverrideMemberChooserObject.BodyType): JetElement {
val newDescriptor = descriptor.copy(descriptor.containingDeclaration, Modality.OPEN, descriptor.visibility,
descriptor.kind, /* copyOverrides = */ true) as PropertyDescriptor
newDescriptor.addOverriddenDescriptor(descriptor)
val body = StringBuilder {
append("\nget()")
append(" = ")
append(generateUnsupportedOrSuperCall(descriptor, bodyType))
if (descriptor.isVar) {
append("\nset(value) {}")
}
}
return JetPsiFactory(classOrObject.project).createProperty(OVERRIDE_RENDERER.render(newDescriptor) + body)
}
private fun overrideFunction(classOrObject: JetClassOrObject, descriptor: FunctionDescriptor, bodyType: OverrideMemberChooserObject.BodyType): JetNamedFunction {
val newDescriptor = descriptor.copy(descriptor.containingDeclaration, Modality.OPEN, descriptor.visibility,
descriptor.kind, /* copyOverrides = */ true)
newDescriptor.addOverriddenDescriptor(descriptor)
val returnType = descriptor.returnType
val returnsNotUnit = returnType != null && !KotlinBuiltIns.isUnit(returnType)
val delegation = generateUnsupportedOrSuperCall(descriptor, bodyType)
val body = "{" + (if (returnsNotUnit && bodyType != OverrideMemberChooserObject.BodyType.EMPTY) "return " else "") + delegation + "}"
return JetPsiFactory(classOrObject.project).createFunction(OVERRIDE_RENDERER.render(newDescriptor) + body)
}
private fun generateUnsupportedOrSuperCall(descriptor: CallableMemberDescriptor, bodyType: OverrideMemberChooserObject.BodyType): String {
if (bodyType == OverrideMemberChooserObject.BodyType.EMPTY) {
return "throw UnsupportedOperationException()"
}
else {
return StringBuilder {
append("super")
if (bodyType == OverrideMemberChooserObject.BodyType.QUALIFIED_SUPER) {
val superClassFqName = IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(descriptor.containingDeclaration as ClassifierDescriptor)
append("<").append(superClassFqName).append(">")
}
append(".").append(descriptor.escapedName())
if (descriptor is FunctionDescriptor) {
val paramTexts = descriptor.valueParameters.map {
val renderedName = it.escapedName()
if (it.varargElementType != null) "*$renderedName" else renderedName
}
paramTexts.joinTo(this, prefix="(", postfix=")")
}
}.toString()
}
}
private fun DeclarationDescriptor.escapedName() = name.render()
}
}
@@ -21,10 +21,13 @@ import com.intellij.codeInsight.generation.MemberChooserObject
import com.intellij.codeInsight.generation.MemberChooserObjectBase
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.core.util.DescriptorMemberChooserObject
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.renderer.*
interface OverrideMemberChooserObject : ClassMember {
enum class BodyType {
@@ -56,7 +59,7 @@ interface OverrideMemberChooserObject : ClassMember {
) : DescriptorMemberChooserObject(declaration, descriptor), OverrideMemberChooserObject {
override val descriptor: CallableMemberDescriptor
get() = super<DescriptorMemberChooserObject>.descriptor as CallableMemberDescriptor
get() = super.descriptor as CallableMemberDescriptor
}
private class WithoutDeclaration(
@@ -72,3 +75,91 @@ interface OverrideMemberChooserObject : ClassMember {
}
}
}
fun OverrideMemberChooserObject.generateMember(project: Project, asConstructorParameter: Boolean = false): JetCallableDeclaration {
val descriptor = immediateSuper
if (asConstructorParameter) {
assert(descriptor is PropertyDescriptor) { "asConstructorParameter is valid only for PropertyDescriptor" }
return generateConstructorParameter(project, descriptor as PropertyDescriptor)
}
return when (descriptor) {
is SimpleFunctionDescriptor -> generateFunction(project, descriptor, bodyType)
is PropertyDescriptor -> generateProperty(project, descriptor, bodyType)
else -> error("Unknown member to override: $descriptor")
}
}
private val OVERRIDE_RENDERER = DescriptorRenderer.withOptions {
renderDefaultValues = false
modifiers = setOf(DescriptorRendererModifier.OVERRIDE)
withDefinedIn = false
nameShortness = NameShortness.SOURCE_CODE_QUALIFIED
overrideRenderingPolicy = OverrideRenderingPolicy.RENDER_OVERRIDE
unitReturnType = false
typeNormalizer = IdeDescriptorRenderers.APPROXIMATE_FLEXIBLE_TYPES
}
private fun generateProperty(project: Project, descriptor: PropertyDescriptor, bodyType: OverrideMemberChooserObject.BodyType): JetProperty {
val newDescriptor = descriptor.copy(descriptor.containingDeclaration, Modality.OPEN, descriptor.visibility,
descriptor.kind, /* copyOverrides = */ true) as PropertyDescriptor
newDescriptor.addOverriddenDescriptor(descriptor)
val body = StringBuilder {
append("\nget()")
append(" = ")
append(generateUnsupportedOrSuperCall(descriptor, bodyType))
if (descriptor.isVar) {
append("\nset(value) {}")
}
}
return JetPsiFactory(project).createProperty(OVERRIDE_RENDERER.render(newDescriptor) + body)
}
private fun generateConstructorParameter(project: Project, descriptor: PropertyDescriptor): JetParameter {
val newDescriptor = descriptor.copy(descriptor.containingDeclaration, Modality.OPEN, descriptor.visibility,
descriptor.kind, /* copyOverrides = */ true) as PropertyDescriptor
newDescriptor.addOverriddenDescriptor(descriptor)
return JetPsiFactory(project).createParameter(OVERRIDE_RENDERER.render(newDescriptor))
}
private fun generateFunction(project: Project, descriptor: FunctionDescriptor, bodyType: OverrideMemberChooserObject.BodyType): JetNamedFunction {
val newDescriptor = descriptor.copy(descriptor.containingDeclaration, Modality.OPEN, descriptor.visibility,
descriptor.kind, /* copyOverrides = */ true)
newDescriptor.addOverriddenDescriptor(descriptor)
val returnType = descriptor.returnType
val returnsNotUnit = returnType != null && !KotlinBuiltIns.isUnit(returnType)
val delegation = generateUnsupportedOrSuperCall(descriptor, bodyType)
val body = "{" + (if (returnsNotUnit && bodyType != OverrideMemberChooserObject.BodyType.EMPTY) "return " else "") + delegation + "}"
return JetPsiFactory(project).createFunction(OVERRIDE_RENDERER.render(newDescriptor) + body)
}
private fun generateUnsupportedOrSuperCall(descriptor: CallableMemberDescriptor, bodyType: OverrideMemberChooserObject.BodyType): String {
if (bodyType == OverrideMemberChooserObject.BodyType.EMPTY) {
return "throw UnsupportedOperationException()"
}
else {
return StringBuilder {
append("super")
if (bodyType == OverrideMemberChooserObject.BodyType.QUALIFIED_SUPER) {
val superClassFqName = IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(descriptor.containingDeclaration as ClassifierDescriptor)
append("<").append(superClassFqName).append(">")
}
append(".").append(descriptor.name.render())
if (descriptor is FunctionDescriptor) {
val paramTexts = descriptor.valueParameters.map {
val renderedName = it.name.render()
if (it.varargElementType != null) "*$renderedName" else renderedName
}
paramTexts.joinTo(this, prefix="(", postfix=")")
}
}.toString()
}
}