Create from Usage: Support primary constructor insertion
This commit is contained in:
@@ -432,12 +432,12 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
|
|||||||
return file.importDirectives
|
return file.importDirectives
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createPrimaryConstructor(): KtPrimaryConstructor {
|
fun createPrimaryConstructor(text: String = ""): KtPrimaryConstructor {
|
||||||
return createClass("class A()").primaryConstructor!!
|
return createClass(if (text.isNotEmpty())"class A $text" else "class A()" ).primaryConstructor!!
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createPrimaryConstructor(modifiers: String?): KtPrimaryConstructor {
|
fun createPrimaryConstructorWithModifiers(modifiers: String?): KtPrimaryConstructor {
|
||||||
return modifiers?.let { createClass("class A $modifiers constructor()").primaryConstructor } ?: createPrimaryConstructor()
|
return modifiers?.let { createPrimaryConstructor("$it constructor()") } ?: createPrimaryConstructor()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createConstructorKeyword(): PsiElement =
|
fun createConstructorKeyword(): PsiElement =
|
||||||
|
|||||||
+1
-1
@@ -158,7 +158,7 @@ class ConvertSecondaryConstructorToPrimaryIntention : SelfTargetingRangeIntentio
|
|||||||
val factory = KtPsiFactory(klass)
|
val factory = KtPsiFactory(klass)
|
||||||
val constructorCommentSaver = CommentSaver(element)
|
val constructorCommentSaver = CommentSaver(element)
|
||||||
val constructorInClass = klass.createPrimaryConstructorIfAbsent()
|
val constructorInClass = klass.createPrimaryConstructorIfAbsent()
|
||||||
val constructor = factory.createPrimaryConstructor(element.modifierList?.text?.replace("\n", " "))
|
val constructor = factory.createPrimaryConstructorWithModifiers(element.modifierList?.text?.replace("\n", " "))
|
||||||
|
|
||||||
val parameterToPropertyMap = mutableMapOf<ValueParameterDescriptor, PropertyDescriptor>()
|
val parameterToPropertyMap = mutableMapOf<ValueParameterDescriptor, PropertyDescriptor>()
|
||||||
val initializer = element.extractInitializer(parameterToPropertyMap, context, factory) ?: return
|
val initializer = element.extractInitializer(parameterToPropertyMap, context, factory) ?: return
|
||||||
|
|||||||
+17
-9
@@ -322,7 +322,7 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
returnTypeCandidate?.theType?.isUnit() ?: false
|
returnTypeCandidate?.theType?.isUnit() ?: false
|
||||||
CallableKind.CLASS_WITH_PRIMARY_CONSTRUCTOR ->
|
CallableKind.CLASS_WITH_PRIMARY_CONSTRUCTOR ->
|
||||||
callableInfo.returnTypeInfo == TypeInfo.Empty || returnTypeCandidate?.theType?.isAnyOrNullableAny() ?: false
|
callableInfo.returnTypeInfo == TypeInfo.Empty || returnTypeCandidate?.theType?.isAnyOrNullableAny() ?: false
|
||||||
CallableKind.SECONDARY_CONSTRUCTOR -> true
|
CallableKind.CONSTRUCTOR -> true
|
||||||
CallableKind.PROPERTY -> containingElement is KtBlockExpression
|
CallableKind.PROPERTY -> containingElement is KtBlockExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -432,18 +432,18 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
if (isFunctionType) "($renderedType)." else "$renderedType."
|
if (isFunctionType) "($renderedType)." else "$renderedType."
|
||||||
} else ""
|
} else ""
|
||||||
|
|
||||||
val classKind = (callableInfo as? PrimaryConstructorInfo)?.classInfo?.kind
|
val classKind = (callableInfo as? ClassWithPrimaryConstructorInfo)?.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 ""
|
||||||
val list = callableInfo.parameterInfos.indices.joinToString(", ") { i -> "${prefix}p$i: Any" }
|
val list = callableInfo.parameterInfos.indices.joinToString(", ") { i -> "${prefix}p$i: Any" }
|
||||||
return if (callableInfo.parameterInfos.isNotEmpty()
|
return if (callableInfo.parameterInfos.isNotEmpty()
|
||||||
|| callableInfo.kind == CallableKind.FUNCTION
|
|| callableInfo.kind == CallableKind.FUNCTION
|
||||||
|| callableInfo.kind == CallableKind.SECONDARY_CONSTRUCTOR) "($list)" else list
|
|| callableInfo.kind == CallableKind.CONSTRUCTOR) "($list)" else list
|
||||||
}
|
}
|
||||||
|
|
||||||
val paramList = when (callableInfo.kind) {
|
val paramList = when (callableInfo.kind) {
|
||||||
CallableKind.FUNCTION, CallableKind.CLASS_WITH_PRIMARY_CONSTRUCTOR, CallableKind.SECONDARY_CONSTRUCTOR ->
|
CallableKind.FUNCTION, CallableKind.CLASS_WITH_PRIMARY_CONSTRUCTOR, CallableKind.CONSTRUCTOR ->
|
||||||
renderParamList()
|
renderParamList()
|
||||||
CallableKind.PROPERTY -> ""
|
CallableKind.PROPERTY -> ""
|
||||||
}
|
}
|
||||||
@@ -459,7 +459,7 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
else if (containingElement is KtClassOrObject
|
else if (containingElement is KtClassOrObject
|
||||||
&& !(containingElement is KtClass && containingElement.isInterface())
|
&& !(containingElement is KtClass && containingElement.isInterface())
|
||||||
&& containingElement.isAncestor(config.originalElement)
|
&& containingElement.isAncestor(config.originalElement)
|
||||||
&& callableInfo.kind != CallableKind.SECONDARY_CONSTRUCTOR) "private "
|
&& callableInfo.kind != CallableKind.CONSTRUCTOR) "private "
|
||||||
else if (isExtension) "private "
|
else if (isExtension) "private "
|
||||||
else ""
|
else ""
|
||||||
|
|
||||||
@@ -468,9 +468,9 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val declaration: KtNamedDeclaration = when (callableInfo.kind) {
|
val declaration: KtNamedDeclaration = when (callableInfo.kind) {
|
||||||
CallableKind.FUNCTION, CallableKind.SECONDARY_CONSTRUCTOR -> {
|
CallableKind.FUNCTION, CallableKind.CONSTRUCTOR -> {
|
||||||
val body = when {
|
val body = when {
|
||||||
callableInfo.kind == CallableKind.SECONDARY_CONSTRUCTOR -> ""
|
callableInfo.kind == CallableKind.CONSTRUCTOR -> ""
|
||||||
callableInfo.isAbstract -> ""
|
callableInfo.isAbstract -> ""
|
||||||
containingElement is KtClass && containingElement.hasModifier(KtTokens.EXTERNAL_KEYWORD) -> ""
|
containingElement is KtClass && containingElement.hasModifier(KtTokens.EXTERNAL_KEYWORD) -> ""
|
||||||
containingElement is KtObjectDeclaration && containingElement.hasModifier(KtTokens.EXTERNAL_KEYWORD) -> ""
|
containingElement is KtObjectDeclaration && containingElement.hasModifier(KtTokens.EXTERNAL_KEYWORD) -> ""
|
||||||
@@ -487,12 +487,16 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
val infixModifier = if (callableInfo.isInfix) "infix " else ""
|
val infixModifier = if (callableInfo.isInfix) "infix " else ""
|
||||||
psiFactory.createFunction("$modifiers$infixModifier${operatorModifier}fun<> $header $body") as KtNamedDeclaration
|
psiFactory.createFunction("$modifiers$infixModifier${operatorModifier}fun<> $header $body") as KtNamedDeclaration
|
||||||
}
|
}
|
||||||
|
else if ((callableInfo as ConstructorInfo).isPrimary) {
|
||||||
|
val constructorText = if (modifiers.isNotEmpty()) "${modifiers}constructor$paramList" else paramList
|
||||||
|
psiFactory.createPrimaryConstructor(constructorText) as KtNamedDeclaration
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
psiFactory.createSecondaryConstructor("${modifiers}constructor$paramList $body") as KtNamedDeclaration
|
psiFactory.createSecondaryConstructor("${modifiers}constructor$paramList $body") as KtNamedDeclaration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CallableKind.CLASS_WITH_PRIMARY_CONSTRUCTOR -> {
|
CallableKind.CLASS_WITH_PRIMARY_CONSTRUCTOR -> {
|
||||||
with((callableInfo as PrimaryConstructorInfo).classInfo) {
|
with((callableInfo as ClassWithPrimaryConstructorInfo).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}"
|
||||||
@@ -824,7 +828,7 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val needStatic = when (callableInfo) {
|
val needStatic = when (callableInfo) {
|
||||||
is PrimaryConstructorInfo -> with(callableInfo.classInfo) {
|
is ClassWithPrimaryConstructorInfo -> 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
|
||||||
@@ -1052,6 +1056,10 @@ internal fun <D : KtNamedDeclaration> placeDeclarationInContainer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val declarationInPlace = when {
|
val declarationInPlace = when {
|
||||||
|
declaration is KtPrimaryConstructor -> {
|
||||||
|
(container as KtClass).createPrimaryConstructorIfAbsent().replaced(declaration) as D
|
||||||
|
}
|
||||||
|
|
||||||
actualContainer.isAncestor(anchor, true) -> {
|
actualContainer.isAncestor(anchor, true) -> {
|
||||||
val insertToBlock = container is KtBlockExpression
|
val insertToBlock = container is KtBlockExpression
|
||||||
if (insertToBlock) {
|
if (insertToBlock) {
|
||||||
|
|||||||
+6
-5
@@ -161,7 +161,7 @@ class ParameterInfo(
|
|||||||
enum class CallableKind {
|
enum class CallableKind {
|
||||||
FUNCTION,
|
FUNCTION,
|
||||||
CLASS_WITH_PRIMARY_CONSTRUCTOR,
|
CLASS_WITH_PRIMARY_CONSTRUCTOR,
|
||||||
SECONDARY_CONSTRUCTOR,
|
CONSTRUCTOR,
|
||||||
PROPERTY
|
PROPERTY
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,7 +206,7 @@ class FunctionInfo(name: String,
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
class PrimaryConstructorInfo(val classInfo: ClassInfo, expectedTypeInfo: TypeInfo): CallableInfo(
|
class ClassWithPrimaryConstructorInfo(val classInfo: ClassInfo, expectedTypeInfo: TypeInfo): CallableInfo(
|
||||||
classInfo.name, TypeInfo.Empty, expectedTypeInfo.forceNotNull(), Collections.emptyList(), classInfo.typeArguments, false
|
classInfo.name, TypeInfo.Empty, expectedTypeInfo.forceNotNull(), Collections.emptyList(), classInfo.typeArguments, false
|
||||||
) {
|
) {
|
||||||
override val kind: CallableKind get() = CallableKind.CLASS_WITH_PRIMARY_CONSTRUCTOR
|
override val kind: CallableKind get() = CallableKind.CLASS_WITH_PRIMARY_CONSTRUCTOR
|
||||||
@@ -215,11 +215,12 @@ class PrimaryConstructorInfo(val classInfo: ClassInfo, expectedTypeInfo: TypeInf
|
|||||||
override fun copy(receiverTypeInfo: TypeInfo, possibleContainers: List<KtElement>, isAbstract: Boolean) = throw UnsupportedOperationException()
|
override fun copy(receiverTypeInfo: TypeInfo, possibleContainers: List<KtElement>, isAbstract: Boolean) = throw UnsupportedOperationException()
|
||||||
}
|
}
|
||||||
|
|
||||||
class SecondaryConstructorInfo(
|
class ConstructorInfo(
|
||||||
override val parameterInfos: List<ParameterInfo>,
|
override val parameterInfos: List<ParameterInfo>,
|
||||||
val targetClass: PsiElement
|
val targetClass: PsiElement,
|
||||||
|
val isPrimary: Boolean = false
|
||||||
): CallableInfo("", TypeInfo.Empty, TypeInfo.Empty, Collections.emptyList(), Collections.emptyList(), false) {
|
): CallableInfo("", TypeInfo.Empty, TypeInfo.Empty, Collections.emptyList(), Collections.emptyList(), false) {
|
||||||
override val kind: CallableKind get() = CallableKind.SECONDARY_CONSTRUCTOR
|
override val kind: CallableKind get() = CallableKind.CONSTRUCTOR
|
||||||
|
|
||||||
override fun copy(receiverTypeInfo: TypeInfo, possibleContainers: List<KtElement>, isAbstract: Boolean) = throw UnsupportedOperationException()
|
override fun copy(receiverTypeInfo: TypeInfo, possibleContainers: List<KtElement>, isAbstract: Boolean) = throw UnsupportedOperationException()
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -322,7 +322,7 @@ sealed class CreateCallableFromCallActionFactory<E : KtExpression>(
|
|||||||
|
|
||||||
val parameters = expression.getParameterInfos()
|
val parameters = expression.getParameterInfos()
|
||||||
|
|
||||||
return SecondaryConstructorInfo(parameters, klass)
|
return ConstructorInfo(parameters, klass)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -89,7 +89,7 @@ abstract class CreateCallableFromUsageFixBase<E : KtElement>(
|
|||||||
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"
|
CallableKind.CONSTRUCTOR -> "secondary constructor"
|
||||||
else -> throw AssertionError("Unexpected callable info: $it")
|
else -> throw AssertionError("Unexpected callable info: $it")
|
||||||
}
|
}
|
||||||
append(kind)
|
append(kind)
|
||||||
@@ -185,7 +185,7 @@ abstract class CreateCallableFromUsageFixBase<E : KtElement>(
|
|||||||
project.executeCommand(text) { callableBuilder.build() }
|
project.executeCommand(text) { callableBuilder.build() }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (callableInfo is SecondaryConstructorInfo) {
|
if (callableInfo is ConstructorInfo) {
|
||||||
runBuilder(CallablePlacement.NoReceiver(callableInfo.targetClass))
|
runBuilder(CallablePlacement.NoReceiver(callableInfo.targetClass))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
|||||||
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallableInfo
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallableInfo
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.ParameterInfo
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.ParameterInfo
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.SecondaryConstructorInfo
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.ConstructorInfo
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||||
import org.jetbrains.kotlin.idea.refactoring.canRefactor
|
import org.jetbrains.kotlin.idea.refactoring.canRefactor
|
||||||
import org.jetbrains.kotlin.psi.KtClass
|
import org.jetbrains.kotlin.psi.KtClass
|
||||||
@@ -65,6 +65,6 @@ object CreateConstructorFromDelegationCallActionFactory : CreateCallableMemberFr
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return SecondaryConstructorInfo(parameters, targetClass)
|
return ConstructorInfo(parameters, targetClass)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -25,7 +25,7 @@ import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
|||||||
import org.jetbrains.kotlin.idea.refactoring.canRefactor
|
import org.jetbrains.kotlin.idea.refactoring.canRefactor
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallableInfo
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.CallableInfo
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.ParameterInfo
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.ParameterInfo
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.SecondaryConstructorInfo
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.ConstructorInfo
|
||||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||||
import org.jetbrains.kotlin.psi.KtClass
|
import org.jetbrains.kotlin.psi.KtClass
|
||||||
import org.jetbrains.kotlin.psi.KtSuperTypeCallEntry
|
import org.jetbrains.kotlin.psi.KtSuperTypeCallEntry
|
||||||
@@ -58,6 +58,6 @@ object CreateConstructorFromSuperTypeCallActionFactory : CreateCallableMemberFro
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return SecondaryConstructorInfo(parameters, targetClass)
|
return ConstructorInfo(parameters, targetClass)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -163,7 +163,7 @@ open class CreateClassFromUsageFix<E : KtElement> protected constructor (
|
|||||||
is PsiPackage -> createFileByPackage(selectedParent, editor, file)
|
is PsiPackage -> createFileByPackage(selectedParent, editor, file)
|
||||||
else -> throw AssertionError("Unexpected element: " + selectedParent.text)
|
else -> throw AssertionError("Unexpected element: " + selectedParent.text)
|
||||||
} ?: return@runWriteAction
|
} ?: return@runWriteAction
|
||||||
val constructorInfo = PrimaryConstructorInfo(classInfo, expectedTypeInfo)
|
val constructorInfo = ClassWithPrimaryConstructorInfo(classInfo, expectedTypeInfo)
|
||||||
val builder = CallableBuilderConfiguration(
|
val builder = CallableBuilderConfiguration(
|
||||||
Collections.singletonList(constructorInfo),
|
Collections.singletonList(constructorInfo),
|
||||||
element as KtElement,
|
element as KtElement,
|
||||||
|
|||||||
Reference in New Issue
Block a user