Create from Usage: Secondary constructor support
This commit is contained in:
@@ -207,6 +207,10 @@ public class JetPsiFactory(private val project: Project) {
|
|||||||
return createDeclaration(funDecl)
|
return createDeclaration(funDecl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public fun createSecondaryConstructor(decl: String): JetSecondaryConstructor {
|
||||||
|
return createClass("class Foo {\n $decl \n}").getSecondaryConstructors().first()
|
||||||
|
}
|
||||||
|
|
||||||
public fun createModifierList(modifier: JetKeywordToken): JetModifierList {
|
public fun createModifierList(modifier: JetKeywordToken): JetModifierList {
|
||||||
return createModifierList(modifier.getValue())
|
return createModifierList(modifier.getValue())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
//To change body of created constructors use File | Settings | File Templates.
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<table border="0" cellpadding="2" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111">
|
||||||
|
<tr>
|
||||||
|
<td colspan="3"><font face="verdana" size="-1">This is a built-in template used for filling the body of a Kotlin secondary
|
||||||
|
constructor each time it is generated by the program, e.g. when using the <b>Create secondary constructor from Usage</b> intention action.<br>
|
||||||
|
The template is editable. Along with Kotlin expressions and comments, you can also use the predefined variables
|
||||||
|
that will be then expanded into the corresponding values.</font>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<table border="0" cellpadding="5" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111">
|
||||||
|
<tr>
|
||||||
|
<td colspan="3"><font face="verdana" size="-1">Predefined variables will take the following values:</font></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td valign="top"><nobr><font face="verdana" size="-2" color="#7F0000"><b><i>${CLASS_NAME}</i></b></font></nobr></td>
|
||||||
|
<td width="10"> </td>
|
||||||
|
<td valign="top"><font face="verdana" size="-1">qualified name of the class where function is created</font></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td valign="top"><nobr><font face="verdana" size="-2" color="#7F0000"><b><i>${SIMPLE_CLASS_NAME}</i></b></font></nobr></td>
|
||||||
|
<td width="10"> </td>
|
||||||
|
<td valign="top"><font face="verdana" size="-1">non-qualified name of the class where function is implemented</font></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
+108
-82
@@ -16,73 +16,61 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder
|
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.daemon.impl.quickfix.CreateFromUsageUtils
|
||||||
import com.intellij.codeInsight.navigation.NavigationUtil
|
import com.intellij.codeInsight.navigation.NavigationUtil
|
||||||
import com.intellij.codeInsight.template.*
|
import com.intellij.codeInsight.template.*
|
||||||
|
import com.intellij.codeInsight.template.impl.TemplateImpl
|
||||||
|
import com.intellij.codeInsight.template.impl.TemplateManagerImpl
|
||||||
import com.intellij.ide.fileTemplates.FileTemplate
|
import com.intellij.ide.fileTemplates.FileTemplate
|
||||||
import com.intellij.ide.fileTemplates.FileTemplateManager
|
import com.intellij.ide.fileTemplates.FileTemplateManager
|
||||||
import com.intellij.openapi.application.ApplicationManager
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
|
import com.intellij.openapi.editor.ScrollType
|
||||||
import com.intellij.openapi.fileEditor.FileEditorManager
|
import com.intellij.openapi.fileEditor.FileEditorManager
|
||||||
|
import com.intellij.openapi.fileEditor.OpenFileDescriptor
|
||||||
import com.intellij.openapi.progress.ProcessCanceledException
|
import com.intellij.openapi.progress.ProcessCanceledException
|
||||||
import com.intellij.psi.PsiDocumentManager
|
import com.intellij.openapi.ui.DialogWrapper
|
||||||
|
import com.intellij.psi.*
|
||||||
|
import com.intellij.psi.codeStyle.JavaCodeStyleManager
|
||||||
import com.intellij.psi.util.PsiTreeUtil
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
import com.intellij.util.IncorrectOperationException
|
import com.intellij.util.IncorrectOperationException
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
|
||||||
import org.jetbrains.kotlin.psi.*
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
|
||||||
import org.jetbrains.kotlin.name.Name
|
|
||||||
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
|
||||||
import org.jetbrains.kotlin.types.*
|
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import kotlin.properties.Delegates
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import java.util.LinkedHashSet
|
|
||||||
import java.util.Collections
|
|
||||||
import java.util.HashMap
|
|
||||||
import java.util.ArrayList
|
|
||||||
import java.util.Properties
|
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
|
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
|
||||||
import com.intellij.psi.PsiWhiteSpace
|
|
||||||
import com.intellij.psi.PsiElement
|
|
||||||
import org.jetbrains.kotlin.lexer.JetTokens
|
|
||||||
import org.jetbrains.kotlin.types.checker.JetTypeChecker
|
|
||||||
import com.intellij.psi.SmartPointerManager
|
|
||||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
import org.jetbrains.kotlin.name.FqName
|
|
||||||
import org.jetbrains.kotlin.descriptors.impl.MutablePackageFragmentDescriptor
|
import org.jetbrains.kotlin.descriptors.impl.MutablePackageFragmentDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
||||||
import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl
|
import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl
|
||||||
import java.util.LinkedHashMap
|
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.ClassKind
|
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
|
|
||||||
import com.intellij.openapi.editor.ScrollType
|
|
||||||
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
|
|
||||||
import com.intellij.psi.PsiClass
|
|
||||||
import com.intellij.codeInsight.daemon.impl.quickfix.CreateFromUsageUtils
|
|
||||||
import com.intellij.psi.PsiMethod
|
|
||||||
import com.intellij.openapi.fileEditor.OpenFileDescriptor
|
|
||||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager
|
|
||||||
import com.intellij.psi.PsiModifier
|
|
||||||
import com.intellij.psi.PsiField
|
|
||||||
import com.intellij.psi.PsiMember
|
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.getJavaClassDescriptor
|
import org.jetbrains.kotlin.idea.caches.resolve.getJavaClassDescriptor
|
||||||
import org.jetbrains.kotlin.resolve.scopes.ChainedScope
|
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
|
||||||
import org.jetbrains.kotlin.resolve.scopes.WritableScopeImpl
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.ClassKind
|
||||||
import org.jetbrains.kotlin.resolve.scopes.RedeclarationHandler
|
|
||||||
import org.jetbrains.kotlin.resolve.scopes.WritableScope
|
|
||||||
import com.intellij.psi.PsiMethodCallExpression
|
|
||||||
import com.intellij.psi.PsiExpressionStatement
|
|
||||||
import org.jetbrains.kotlin.idea.refactoring.*
|
import org.jetbrains.kotlin.idea.refactoring.*
|
||||||
import org.jetbrains.kotlin.idea.util.*
|
import org.jetbrains.kotlin.idea.util.*
|
||||||
import com.intellij.openapi.ui.*
|
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
|
||||||
import com.intellij.codeInsight.template.impl.*
|
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||||
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
|
import org.jetbrains.kotlin.lexer.JetTokens
|
||||||
import org.jetbrains.kotlin.idea.util.application.*
|
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.isAncestor
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.siblings
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||||
|
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.*
|
||||||
|
import org.jetbrains.kotlin.types.JetType
|
||||||
|
import org.jetbrains.kotlin.types.TypeProjectionImpl
|
||||||
|
import org.jetbrains.kotlin.types.Variance
|
||||||
|
import org.jetbrains.kotlin.types.checker.JetTypeChecker
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.properties.Delegates
|
||||||
|
|
||||||
private val TYPE_PARAMETER_LIST_VARIABLE_NAME = "typeParameterList"
|
private val TYPE_PARAMETER_LIST_VARIABLE_NAME = "typeParameterList"
|
||||||
private val TEMPLATE_FROM_USAGE_FUNCTION_BODY = "New Kotlin Function Body.kt"
|
private val TEMPLATE_FROM_USAGE_FUNCTION_BODY = "New Kotlin Function Body.kt"
|
||||||
|
private val TEMPLATE_FROM_USAGE_SECONDARY_CONSTRUCTOR_BODY = "New Kotlin Secondary Constructor Body.kt"
|
||||||
private val ATTRIBUTE_FUNCTION_NAME = "FUNCTION_NAME"
|
private val ATTRIBUTE_FUNCTION_NAME = "FUNCTION_NAME"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -322,8 +310,9 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
skipReturnType = when (callableInfo.kind) {
|
skipReturnType = when (callableInfo.kind) {
|
||||||
CallableKind.FUNCTION ->
|
CallableKind.FUNCTION ->
|
||||||
returnTypeCandidate?.theType?.isUnit() ?: false
|
returnTypeCandidate?.theType?.isUnit() ?: false
|
||||||
CallableKind.CONSTRUCTOR ->
|
CallableKind.CLASS_WITH_PRIMARY_CONSTRUCTOR ->
|
||||||
callableInfo.returnTypeInfo == TypeInfo.Empty || returnTypeCandidate?.theType?.isAny() ?: false
|
callableInfo.returnTypeInfo == TypeInfo.Empty || returnTypeCandidate?.theType?.isAny() ?: false
|
||||||
|
CallableKind.SECONDARY_CONSTRUCTOR -> true
|
||||||
CallableKind.PROPERTY -> containingElement is JetBlockExpression
|
CallableKind.PROPERTY -> containingElement is JetBlockExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -437,7 +426,7 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
|
|
||||||
val ownerTypeString = if (isExtension) "${receiverTypeCandidate!!.renderedType!!}." else ""
|
val ownerTypeString = if (isExtension) "${receiverTypeCandidate!!.renderedType!!}." else ""
|
||||||
|
|
||||||
val classKind = (callableInfo as? ConstructorInfo)?.classInfo?.kind
|
val classKind = (callableInfo as? PrimaryConstructorInfo)?.classInfo?.kind
|
||||||
|
|
||||||
fun renderParamList(): String {
|
fun renderParamList(): String {
|
||||||
val prefix = if (classKind == ClassKind.ANNOTATION_CLASS) "val " else ""
|
val prefix = if (classKind == ClassKind.ANNOTATION_CLASS) "val " else ""
|
||||||
@@ -446,7 +435,8 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val paramList = when (callableInfo.kind) {
|
val paramList = when (callableInfo.kind) {
|
||||||
CallableKind.FUNCTION, CallableKind.CONSTRUCTOR -> renderParamList()
|
CallableKind.FUNCTION, CallableKind.CLASS_WITH_PRIMARY_CONSTRUCTOR, CallableKind.SECONDARY_CONSTRUCTOR ->
|
||||||
|
renderParamList()
|
||||||
CallableKind.PROPERTY -> ""
|
CallableKind.PROPERTY -> ""
|
||||||
}
|
}
|
||||||
val returnTypeString = if (skipReturnType || assignmentToReplace != null) "" else ": Any"
|
val returnTypeString = if (skipReturnType || assignmentToReplace != null) "" else ": Any"
|
||||||
@@ -455,20 +445,27 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
val psiFactory = JetPsiFactory(currentFile)
|
val psiFactory = JetPsiFactory(currentFile)
|
||||||
|
|
||||||
val modifiers =
|
val modifiers =
|
||||||
if (containingElement is JetClassOrObject && containingElement.isAncestor(config.originalElement))
|
if (containingElement is JetClassOrObject
|
||||||
|
&& containingElement.isAncestor(config.originalElement)
|
||||||
|
&& callableInfo.kind != CallableKind.SECONDARY_CONSTRUCTOR)
|
||||||
"private "
|
"private "
|
||||||
else ""
|
else ""
|
||||||
|
|
||||||
val declaration : JetNamedDeclaration = when (callableInfo.kind) {
|
val declaration : JetNamedDeclaration = when (callableInfo.kind) {
|
||||||
CallableKind.FUNCTION -> {
|
CallableKind.FUNCTION, CallableKind.SECONDARY_CONSTRUCTOR -> {
|
||||||
val body = when {
|
val body = when {
|
||||||
containingElement is JetClass && containingElement.isTrait() && !config.isExtension -> ""
|
containingElement is JetClass && containingElement.isTrait() && !config.isExtension -> ""
|
||||||
else -> "{}"
|
else -> "{}"
|
||||||
}
|
}
|
||||||
psiFactory.createFunction("${modifiers}fun<> $header $body")
|
if (callableInfo.kind == CallableKind.FUNCTION) {
|
||||||
|
psiFactory.createFunction("${modifiers}fun<> $header $body")
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
psiFactory.createSecondaryConstructor("${modifiers}constructor$paramList $body")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
CallableKind.CONSTRUCTOR -> {
|
CallableKind.CLASS_WITH_PRIMARY_CONSTRUCTOR -> {
|
||||||
with((callableInfo as ConstructorInfo).classInfo) {
|
with((callableInfo as PrimaryConstructorInfo).classInfo) {
|
||||||
val classBody = when (kind) {
|
val classBody = when (kind) {
|
||||||
ClassKind.ANNOTATION_CLASS, ClassKind.ENUM_ENTRY -> ""
|
ClassKind.ANNOTATION_CLASS, ClassKind.ENUM_ENTRY -> ""
|
||||||
else -> "{\n\n}"
|
else -> "{\n\n}"
|
||||||
@@ -557,23 +554,19 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
|
|
||||||
containingElement is JetFile -> containingElement.add(declaration) as JetNamedDeclaration
|
containingElement is JetFile -> containingElement.add(declaration) as JetNamedDeclaration
|
||||||
|
|
||||||
containingElement is PsiClass -> jetFileToEdit.add(declaration) as JetNamedDeclaration
|
containingElement is PsiClass -> {
|
||||||
|
if (declaration is JetSecondaryConstructor) {
|
||||||
|
val wrappingClass = psiFactory.createClass("class ${containingElement.getName()} {\n}")
|
||||||
|
addDeclarationToClassOrObject(wrappingClass, declaration, psiFactory)
|
||||||
|
(jetFileToEdit.add(wrappingClass) as JetClass).getDeclarations().first() as JetNamedDeclaration
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
jetFileToEdit.add(declaration) as JetNamedDeclaration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
containingElement is JetClassOrObject -> {
|
containingElement is JetClassOrObject -> {
|
||||||
var classBody = containingElement.getBody()
|
addDeclarationToClassOrObject(containingElement, declaration, psiFactory)
|
||||||
if (classBody == null) {
|
|
||||||
classBody = containingElement.add(psiFactory.createEmptyClassBody()) as JetClassBody
|
|
||||||
containingElement.addBefore(psiFactory.createWhiteSpace(), classBody)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (declaration is JetNamedFunction) {
|
|
||||||
val anchor = PsiTreeUtil.skipSiblingsBackward(
|
|
||||||
classBody!!.getRBrace() ?: classBody!!.getLastChild()!!,
|
|
||||||
javaClass<PsiWhiteSpace>()
|
|
||||||
)
|
|
||||||
classBody.addAfter(declaration, anchor) as JetNamedDeclaration
|
|
||||||
}
|
|
||||||
else classBody.addAfter(declaration, classBody!!.getLBrace()!!) as JetNamedDeclaration
|
|
||||||
}
|
}
|
||||||
else -> throw AssertionError("Invalid containing element: ${containingElement.getText()}")
|
else -> throw AssertionError("Invalid containing element: ${containingElement.getText()}")
|
||||||
}
|
}
|
||||||
@@ -590,6 +583,25 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun addDeclarationToClassOrObject(classOrObject: JetClassOrObject,
|
||||||
|
declaration: JetNamedDeclaration,
|
||||||
|
psiFactory: JetPsiFactory): JetNamedDeclaration {
|
||||||
|
var classBody = classOrObject.getBody()
|
||||||
|
if (classBody == null) {
|
||||||
|
classBody = classOrObject.add(psiFactory.createEmptyClassBody()) as JetClassBody
|
||||||
|
classOrObject.addBefore(psiFactory.createWhiteSpace(), classBody)
|
||||||
|
}
|
||||||
|
|
||||||
|
return if (declaration is JetNamedFunction) {
|
||||||
|
val anchor = PsiTreeUtil.skipSiblingsBackward(
|
||||||
|
classBody!!.getRBrace() ?: classBody!!.getLastChild()!!,
|
||||||
|
javaClass<PsiWhiteSpace>()
|
||||||
|
)
|
||||||
|
classBody.addAfter(declaration, anchor) as JetNamedDeclaration
|
||||||
|
}
|
||||||
|
else classBody.addAfter(declaration, classBody!!.getLBrace()!!) as JetNamedDeclaration
|
||||||
|
}
|
||||||
|
|
||||||
private fun getTypeParameterRenames(scope: JetScope): Map<TypeParameterDescriptor, String> {
|
private fun getTypeParameterRenames(scope: JetScope): Map<TypeParameterDescriptor, String> {
|
||||||
val allTypeParametersNotInScope = LinkedHashSet<TypeParameterDescriptor>()
|
val allTypeParametersNotInScope = LinkedHashSet<TypeParameterDescriptor>()
|
||||||
|
|
||||||
@@ -660,17 +672,24 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
return typeRefsToShorten
|
return typeRefsToShorten
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupFunctionBody(func: JetNamedFunction) {
|
private fun setupFunctionBody(func: JetFunction) {
|
||||||
val oldBody = func.getBodyExpression() ?: return
|
val oldBody = func.getBodyExpression() ?: return
|
||||||
|
|
||||||
val fileTemplate = FileTemplateManager.getInstance()!!.getCodeTemplate(TEMPLATE_FROM_USAGE_FUNCTION_BODY)
|
val templateName = when (func) {
|
||||||
|
is JetSecondaryConstructor -> TEMPLATE_FROM_USAGE_SECONDARY_CONSTRUCTOR_BODY
|
||||||
|
is JetNamedFunction -> TEMPLATE_FROM_USAGE_FUNCTION_BODY
|
||||||
|
else -> throw AssertionError("Unexpected declaration: " + JetPsiUtil.getElementTextWithContext(func))
|
||||||
|
}
|
||||||
|
val fileTemplate = FileTemplateManager.getInstance()!!.getCodeTemplate(templateName)
|
||||||
val properties = Properties()
|
val properties = Properties()
|
||||||
properties.setProperty(FileTemplate.ATTRIBUTE_RETURN_TYPE, if (skipReturnType) "Unit" else func.getTypeReference()!!.getText())
|
properties.setProperty(FileTemplate.ATTRIBUTE_RETURN_TYPE, if (skipReturnType) "Unit" else func.getTypeReference()!!.getText())
|
||||||
receiverClassDescriptor?.let {
|
receiverClassDescriptor?.let {
|
||||||
properties.setProperty(FileTemplate.ATTRIBUTE_CLASS_NAME, DescriptorUtils.getFqName(it).asString())
|
properties.setProperty(FileTemplate.ATTRIBUTE_CLASS_NAME, DescriptorUtils.getFqName(it).asString())
|
||||||
properties.setProperty(FileTemplate.ATTRIBUTE_SIMPLE_CLASS_NAME, it.getName().asString())
|
properties.setProperty(FileTemplate.ATTRIBUTE_SIMPLE_CLASS_NAME, it.getName().asString())
|
||||||
}
|
}
|
||||||
properties.setProperty(ATTRIBUTE_FUNCTION_NAME, callableInfo.name)
|
if (callableInfo.name.isNotEmpty()) {
|
||||||
|
properties.setProperty(ATTRIBUTE_FUNCTION_NAME, callableInfo.name)
|
||||||
|
}
|
||||||
|
|
||||||
val bodyText = try {
|
val bodyText = try {
|
||||||
fileTemplate!!.getText(properties)
|
fileTemplate!!.getText(properties)
|
||||||
@@ -766,7 +785,7 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
val expression = TypeParameterListExpression(
|
val expression = TypeParameterListExpression(
|
||||||
mandatoryTypeParameters,
|
mandatoryTypeParameters,
|
||||||
typeParameterMap,
|
typeParameterMap,
|
||||||
callableInfo.kind != CallableKind.CONSTRUCTOR
|
callableInfo.kind != CallableKind.CLASS_WITH_PRIMARY_CONSTRUCTOR
|
||||||
)
|
)
|
||||||
builder.replaceElement(typeParameterList, expression, false)
|
builder.replaceElement(typeParameterList, expression, false)
|
||||||
return expression
|
return expression
|
||||||
@@ -831,8 +850,8 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return when (adjustedDeclaration) {
|
return when (adjustedDeclaration) {
|
||||||
is JetNamedFunction -> {
|
is JetNamedFunction, is JetSecondaryConstructor -> {
|
||||||
createJavaMethod(adjustedDeclaration, targetClass)
|
createJavaMethod(adjustedDeclaration as JetFunction, targetClass)
|
||||||
}
|
}
|
||||||
is JetProperty -> {
|
is JetProperty -> {
|
||||||
createJavaField(adjustedDeclaration, targetClass)
|
createJavaField(adjustedDeclaration, targetClass)
|
||||||
@@ -859,7 +878,7 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val needStatic = when (callableInfo) {
|
val needStatic = when (callableInfo) {
|
||||||
is ConstructorInfo -> with(callableInfo.classInfo) {
|
is PrimaryConstructorInfo -> with(callableInfo.classInfo) {
|
||||||
!inner && kind != ClassKind.ENUM_ENTRY && kind != ClassKind.ENUM_CLASS
|
!inner && kind != ClassKind.ENUM_ENTRY && kind != ClassKind.ENUM_CLASS
|
||||||
}
|
}
|
||||||
else -> callableInfo.receiverTypeInfo.staticContextRequired
|
else -> callableInfo.receiverTypeInfo.staticContextRequired
|
||||||
@@ -896,7 +915,12 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
val caretModel = containingFileEditor.getCaretModel()
|
val caretModel = containingFileEditor.getCaretModel()
|
||||||
val selectionModel = containingFileEditor.getSelectionModel()
|
val selectionModel = containingFileEditor.getSelectionModel()
|
||||||
|
|
||||||
caretModel.moveToOffset(declaration.getNameIdentifier().getTextRange().getEndOffset())
|
if (declaration is JetSecondaryConstructor) {
|
||||||
|
caretModel.moveToOffset(declaration.getConstructorKeyword().getTextRange().getEndOffset())
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
caretModel.moveToOffset(declaration.getNameIdentifier()!!.getTextRange().getEndOffset())
|
||||||
|
}
|
||||||
|
|
||||||
fun positionBetween(left: PsiElement, right: PsiElement) {
|
fun positionBetween(left: PsiElement, right: PsiElement) {
|
||||||
val from = left.siblings(withItself = false, forward = true).firstOrNull { it !is PsiWhiteSpace } ?: return
|
val from = left.siblings(withItself = false, forward = true).firstOrNull { it !is PsiWhiteSpace } ?: return
|
||||||
@@ -908,8 +932,10 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
when (declaration) {
|
when (declaration) {
|
||||||
is JetNamedFunction -> {
|
is JetNamedFunction, is JetSecondaryConstructor -> {
|
||||||
(declaration.getBodyExpression() as? JetBlockExpression)?.let { positionBetween(it.getLBrace(), it.getRBrace()) }
|
((declaration as JetFunction).getBodyExpression() as? JetBlockExpression)?.let {
|
||||||
|
positionBetween(it.getLBrace(), it.getRBrace())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
is JetClassOrObject -> {
|
is JetClassOrObject -> {
|
||||||
caretModel.moveToOffset(declaration.getTextRange().getStartOffset())
|
caretModel.moveToOffset(declaration.getTextRange().getStartOffset())
|
||||||
@@ -995,8 +1021,8 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
|
|
||||||
runWriteAction {
|
runWriteAction {
|
||||||
// file templates
|
// file templates
|
||||||
if (newDeclaration is JetNamedFunction) {
|
if (newDeclaration is JetNamedFunction || newDeclaration is JetSecondaryConstructor) {
|
||||||
setupFunctionBody(newDeclaration)
|
setupFunctionBody(newDeclaration as JetFunction)
|
||||||
}
|
}
|
||||||
|
|
||||||
val callElement = config.originalElement as? JetCallElement
|
val callElement = config.originalElement as? JetCallElement
|
||||||
|
|||||||
+12
-3
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder
|
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder
|
||||||
|
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
import java.util.Collections
|
import java.util.Collections
|
||||||
import org.jetbrains.kotlin.psi.JetExpression
|
import org.jetbrains.kotlin.psi.JetExpression
|
||||||
import org.jetbrains.kotlin.types.Variance
|
import org.jetbrains.kotlin.types.Variance
|
||||||
@@ -119,7 +120,8 @@ class ParameterInfo(
|
|||||||
|
|
||||||
enum class CallableKind {
|
enum class CallableKind {
|
||||||
FUNCTION
|
FUNCTION
|
||||||
CONSTRUCTOR
|
CLASS_WITH_PRIMARY_CONSTRUCTOR
|
||||||
|
SECONDARY_CONSTRUCTOR
|
||||||
PROPERTY
|
PROPERTY
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,13 +146,20 @@ class FunctionInfo(name: String,
|
|||||||
override val kind: CallableKind get() = CallableKind.FUNCTION
|
override val kind: CallableKind get() = CallableKind.FUNCTION
|
||||||
}
|
}
|
||||||
|
|
||||||
class ConstructorInfo(val classInfo: ClassInfo, expectedTypeInfo: TypeInfo): CallableInfo(
|
class PrimaryConstructorInfo(val classInfo: ClassInfo, expectedTypeInfo: TypeInfo): CallableInfo(
|
||||||
classInfo.name, TypeInfo.Empty, expectedTypeInfo.forceNotNull(), Collections.emptyList(), classInfo.typeArguments
|
classInfo.name, TypeInfo.Empty, expectedTypeInfo.forceNotNull(), Collections.emptyList(), classInfo.typeArguments
|
||||||
) {
|
) {
|
||||||
override val kind: CallableKind get() = CallableKind.CONSTRUCTOR
|
override val kind: CallableKind get() = CallableKind.CLASS_WITH_PRIMARY_CONSTRUCTOR
|
||||||
override val parameterInfos: List<ParameterInfo> get() = classInfo.parameterInfos
|
override val parameterInfos: List<ParameterInfo> get() = classInfo.parameterInfos
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SecondaryConstructorInfo(
|
||||||
|
override val parameterInfos: List<ParameterInfo>,
|
||||||
|
val targetClass: PsiElement
|
||||||
|
): CallableInfo("", TypeInfo.Empty, TypeInfo.Empty, Collections.emptyList(), Collections.emptyList()) {
|
||||||
|
override val kind: CallableKind get() = CallableKind.SECONDARY_CONSTRUCTOR
|
||||||
|
}
|
||||||
|
|
||||||
class PropertyInfo(name: String,
|
class PropertyInfo(name: String,
|
||||||
receiverTypeInfo: TypeInfo,
|
receiverTypeInfo: TypeInfo,
|
||||||
returnTypeInfo: TypeInfo,
|
returnTypeInfo: TypeInfo,
|
||||||
|
|||||||
+18
-17
@@ -16,25 +16,20 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable
|
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable
|
||||||
|
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.CreateFromUsageFixBase
|
|
||||||
import org.jetbrains.kotlin.psi.JetFile
|
|
||||||
import com.intellij.openapi.editor.Editor
|
|
||||||
import org.jetbrains.kotlin.idea.JetBundle
|
|
||||||
import com.intellij.openapi.project.Project
|
|
||||||
import com.intellij.openapi.command.CommandProcessor
|
import com.intellij.openapi.command.CommandProcessor
|
||||||
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
import com.intellij.openapi.editor.Editor
|
||||||
import org.jetbrains.kotlin.psi.JetClassOrObject
|
import com.intellij.openapi.project.Project
|
||||||
import org.jetbrains.kotlin.idea.refactoring.chooseContainerElementIfNecessary
|
|
||||||
import org.jetbrains.kotlin.psi.JetClassBody
|
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
|
|
||||||
import org.jetbrains.kotlin.psi.JetExpression
|
|
||||||
import java.util.HashSet
|
|
||||||
import org.jetbrains.kotlin.psi.JetElement
|
|
||||||
import com.intellij.psi.PsiClass
|
import com.intellij.psi.PsiClass
|
||||||
import java.util.Collections
|
|
||||||
import org.jetbrains.kotlin.psi.JetPsiUtil
|
|
||||||
import org.jetbrains.kotlin.idea.refactoring.canRefactor
|
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
|
import org.jetbrains.kotlin.idea.JetBundle
|
||||||
|
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
||||||
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.CreateFromUsageFixBase
|
||||||
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
|
||||||
|
import org.jetbrains.kotlin.idea.refactoring.canRefactor
|
||||||
|
import org.jetbrains.kotlin.idea.refactoring.chooseContainerElementIfNecessary
|
||||||
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import java.util.Collections
|
||||||
|
import java.util.HashSet
|
||||||
|
|
||||||
public class CreateCallableFromUsageFix(
|
public class CreateCallableFromUsageFix(
|
||||||
originalExpression: JetExpression,
|
originalExpression: JetExpression,
|
||||||
@@ -64,9 +59,10 @@ public class CreateCallableFromUsageFix(
|
|||||||
val kind = when (it.kind) {
|
val kind = when (it.kind) {
|
||||||
CallableKind.FUNCTION -> "function"
|
CallableKind.FUNCTION -> "function"
|
||||||
CallableKind.PROPERTY -> "property"
|
CallableKind.PROPERTY -> "property"
|
||||||
|
CallableKind.SECONDARY_CONSTRUCTOR -> "secondary constructor"
|
||||||
else -> throw AssertionError("Unexpected callable info: $it")
|
else -> throw AssertionError("Unexpected callable info: $it")
|
||||||
}
|
}
|
||||||
"$kind '${it.name}'"
|
if (it.name.isNotEmpty()) "$kind '${it.name}'" else kind
|
||||||
}
|
}
|
||||||
return JetBundle.message(
|
return JetBundle.message(
|
||||||
"create.0.from.usage",
|
"create.0.from.usage",
|
||||||
@@ -114,6 +110,11 @@ public class CreateCallableFromUsageFix(
|
|||||||
CommandProcessor.getInstance().executeCommand(project, { callableBuilder.build() }, getText(), null)
|
CommandProcessor.getInstance().executeCommand(project, { callableBuilder.build() }, getText(), null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (callableInfo is SecondaryConstructorInfo) {
|
||||||
|
runBuilder(CallablePlacement.NoReceiver(callableInfo.targetClass))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val popupTitle = JetBundle.message("choose.target.class.or.trait.title")
|
val popupTitle = JetBundle.message("choose.target.class.or.trait.title")
|
||||||
val receiverTypeCandidates = callableBuilder.computeTypeCandidates(callableInfo.receiverTypeInfo)
|
val receiverTypeCandidates = callableBuilder.computeTypeCandidates(callableInfo.receiverTypeInfo)
|
||||||
if (receiverTypeCandidates.isNotEmpty()) {
|
if (receiverTypeCandidates.isNotEmpty()) {
|
||||||
|
|||||||
+2
-7
@@ -26,14 +26,8 @@ import com.intellij.psi.PsiElement
|
|||||||
import com.intellij.psi.PsiDirectory
|
import com.intellij.psi.PsiDirectory
|
||||||
import org.jetbrains.kotlin.idea.JetFileType
|
import org.jetbrains.kotlin.idea.JetFileType
|
||||||
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
|
import org.jetbrains.kotlin.idea.codeInsight.CodeInsightUtils
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.ParameterInfo
|
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.ConstructorInfo
|
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallableBuilderConfiguration
|
|
||||||
import java.util.Collections
|
import java.util.Collections
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.createBuilder
|
|
||||||
import com.intellij.openapi.command.CommandProcessor
|
import com.intellij.openapi.command.CommandProcessor
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallablePlacement
|
|
||||||
import org.jetbrains.kotlin.idea.refactoring.getOrCreateKotlinFile
|
import org.jetbrains.kotlin.idea.refactoring.getOrCreateKotlinFile
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.ClassKind.*
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass.ClassKind.*
|
||||||
import com.intellij.psi.PsiPackage
|
import com.intellij.psi.PsiPackage
|
||||||
@@ -45,6 +39,7 @@ import org.jetbrains.kotlin.idea.refactoring.canRefactor
|
|||||||
import com.intellij.psi.PsiMember
|
import com.intellij.psi.PsiMember
|
||||||
import com.intellij.psi.PsiClass
|
import com.intellij.psi.PsiClass
|
||||||
import com.intellij.psi.PsiFile
|
import com.intellij.psi.PsiFile
|
||||||
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
|
||||||
|
|
||||||
enum class ClassKind(val keyword: String, val description: String) {
|
enum class ClassKind(val keyword: String, val description: String) {
|
||||||
PLAIN_CLASS: ClassKind("class", "class")
|
PLAIN_CLASS: ClassKind("class", "class")
|
||||||
@@ -124,7 +119,7 @@ public class CreateClassFromUsageFix(
|
|||||||
else -> throw AssertionError("Unexpected element: " + targetParent.getText())
|
else -> throw AssertionError("Unexpected element: " + targetParent.getText())
|
||||||
} ?: return
|
} ?: return
|
||||||
|
|
||||||
val constructorInfo = ConstructorInfo(classInfo, expectedTypeInfo)
|
val constructorInfo = PrimaryConstructorInfo(classInfo, expectedTypeInfo)
|
||||||
val builder = CallableBuilderConfiguration(
|
val builder = CallableBuilderConfiguration(
|
||||||
Collections.singletonList(constructorInfo), element as JetElement, file, editor, false, kind == PLAIN_CLASS || kind == TRAIT
|
Collections.singletonList(constructorInfo), element as JetElement, file, editor, false, kind == PLAIN_CLASS || kind == TRAIT
|
||||||
).createBuilder()
|
).createBuilder()
|
||||||
|
|||||||
@@ -481,7 +481,7 @@ private fun copyTypeParameters<T: PsiTypeParameterListOwner>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun createJavaMethod(function: JetNamedFunction, targetClass: PsiClass): PsiMethod {
|
public fun createJavaMethod(function: JetFunction, targetClass: PsiClass): PsiMethod {
|
||||||
val template = LightClassUtil.getLightClassMethod(function)
|
val template = LightClassUtil.getLightClassMethod(function)
|
||||||
?: throw AssertionError("Can't generate light method: ${JetPsiUtil.getElementTextWithContext(function)}")
|
?: throw AssertionError("Can't generate light method: ${JetPsiUtil.getElementTextWithContext(function)}")
|
||||||
return createJavaMethod(template, targetClass)
|
return createJavaMethod(template, targetClass)
|
||||||
|
|||||||
Reference in New Issue
Block a user