Override/Implement: Use function body template when generating functions with default body

#KT-11807 Fixed
This commit is contained in:
Alexey Sedunov
2016-04-18 16:33:17 +03:00
parent df07554764
commit 1635018fe7
60 changed files with 165 additions and 116 deletions
@@ -24,6 +24,8 @@ import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.core.TemplateKind
import org.jetbrains.kotlin.idea.core.getFunctionBodyTextFromTemplate
import org.jetbrains.kotlin.idea.core.util.DescriptorMemberChooserObject
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.psi.*
@@ -115,7 +117,7 @@ private fun generateProperty(project: Project, descriptor: PropertyDescriptor, b
val body = buildString {
append("\nget()")
append(" = ")
append(generateUnsupportedOrSuperCall(descriptor, bodyType))
append(generateUnsupportedOrSuperCall(project, descriptor, bodyType))
if (descriptor.isVar) {
append("\nset(value) {}")
}
@@ -139,17 +141,26 @@ private fun generateFunction(project: Project, descriptor: FunctionDescriptor, b
val returnsNotUnit = returnType != null && !KotlinBuiltIns.isUnit(returnType)
val body = if (bodyType != OverrideMemberChooserObject.BodyType.NO_BODY) {
val delegation = generateUnsupportedOrSuperCall(descriptor, bodyType)
"{" + (if (returnsNotUnit && bodyType != OverrideMemberChooserObject.BodyType.EMPTY) "return " else "") + delegation + "}"
val delegation = generateUnsupportedOrSuperCall(project, descriptor, bodyType)
"{" + (if (returnsNotUnit && bodyType != OverrideMemberChooserObject.BodyType.EMPTY) "return " else "") + delegation + "\n}"
}
else ""
return KtPsiFactory(project).createFunction(OVERRIDE_RENDERER.render(newDescriptor) + body)
}
fun generateUnsupportedOrSuperCall(descriptor: CallableMemberDescriptor, bodyType: OverrideMemberChooserObject.BodyType): String {
fun generateUnsupportedOrSuperCall(
project: Project,
descriptor: CallableMemberDescriptor,
bodyType: OverrideMemberChooserObject.BodyType
): String {
if (bodyType == OverrideMemberChooserObject.BodyType.EMPTY) {
return "throw UnsupportedOperationException()"
if (descriptor !is FunctionDescriptor) return "throw UnsupportedOperationException()"
return getFunctionBodyTextFromTemplate(project,
TemplateKind.FUNCTION,
descriptor.name.asString(),
descriptor.returnType?.let { IdeDescriptorRenderers.SOURCE_CODE.renderType(it) } ?: "Unit",
null)
}
else {
return buildString {
@@ -165,7 +176,7 @@ fun generateUnsupportedOrSuperCall(descriptor: CallableMemberDescriptor, bodyTyp
val renderedName = it.name.render()
if (it.varargElementType != null) "*$renderedName" else renderedName
}
paramTexts.joinTo(this, prefix="(", postfix=")")
paramTexts.joinTo(this, prefix = "(", postfix = ")")
}
}
}
@@ -0,0 +1,65 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.core
import com.intellij.ide.fileTemplates.FileTemplate
import com.intellij.ide.fileTemplates.FileTemplateManager
import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.openapi.project.Project
import com.intellij.util.IncorrectOperationException
import org.jetbrains.kotlin.name.FqName
import java.util.*
private val FUNCTION_BODY_TEMPLATE = "New Kotlin Function Body.kt"
private val SECONDARY_CONSTRUCTOR_BODY_TEMPLATE = "New Kotlin Secondary Constructor Body.kt"
private val ATTRIBUTE_FUNCTION_NAME = "FUNCTION_NAME"
enum class TemplateKind(val templateFileName: String) {
FUNCTION(FUNCTION_BODY_TEMPLATE), SECONDARY_CONSTRUCTOR(SECONDARY_CONSTRUCTOR_BODY_TEMPLATE)
}
fun getFunctionBodyTextFromTemplate(
project: Project,
kind: TemplateKind,
name: String?,
returnType: String,
classFqName: FqName? = null
): String {
val fileTemplate = FileTemplateManager.getInstance(project)!!.getCodeTemplate(kind.templateFileName)
val properties = Properties()
properties.setProperty(FileTemplate.ATTRIBUTE_RETURN_TYPE, returnType)
if (classFqName != null) {
properties.setProperty(FileTemplate.ATTRIBUTE_CLASS_NAME, classFqName.asString())
properties.setProperty(FileTemplate.ATTRIBUTE_SIMPLE_CLASS_NAME, classFqName.shortName().asString())
}
if (name != null) {
properties.setProperty(ATTRIBUTE_FUNCTION_NAME, name)
}
return try {
fileTemplate!!.getText(properties)
}
catch (e: ProcessCanceledException) {
throw e
}
catch (e: Throwable) {
// TODO: This is dangerous.
// Is there any way to avoid catching all exceptions?
throw IncorrectOperationException("Failed to parse file template", e)
}
}