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
|
||||
}
|
||||
|
||||
fun createPrimaryConstructor(): KtPrimaryConstructor {
|
||||
return createClass("class A()").primaryConstructor!!
|
||||
fun createPrimaryConstructor(text: String = ""): KtPrimaryConstructor {
|
||||
return createClass(if (text.isNotEmpty())"class A $text" else "class A()" ).primaryConstructor!!
|
||||
}
|
||||
|
||||
fun createPrimaryConstructor(modifiers: String?): KtPrimaryConstructor {
|
||||
return modifiers?.let { createClass("class A $modifiers constructor()").primaryConstructor } ?: createPrimaryConstructor()
|
||||
fun createPrimaryConstructorWithModifiers(modifiers: String?): KtPrimaryConstructor {
|
||||
return modifiers?.let { createPrimaryConstructor("$it constructor()") } ?: createPrimaryConstructor()
|
||||
}
|
||||
|
||||
fun createConstructorKeyword(): PsiElement =
|
||||
|
||||
+1
-1
@@ -158,7 +158,7 @@ class ConvertSecondaryConstructorToPrimaryIntention : SelfTargetingRangeIntentio
|
||||
val factory = KtPsiFactory(klass)
|
||||
val constructorCommentSaver = CommentSaver(element)
|
||||
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 initializer = element.extractInitializer(parameterToPropertyMap, context, factory) ?: return
|
||||
|
||||
+17
-9
@@ -322,7 +322,7 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
||||
returnTypeCandidate?.theType?.isUnit() ?: false
|
||||
CallableKind.CLASS_WITH_PRIMARY_CONSTRUCTOR ->
|
||||
callableInfo.returnTypeInfo == TypeInfo.Empty || returnTypeCandidate?.theType?.isAnyOrNullableAny() ?: false
|
||||
CallableKind.SECONDARY_CONSTRUCTOR -> true
|
||||
CallableKind.CONSTRUCTOR -> true
|
||||
CallableKind.PROPERTY -> containingElement is KtBlockExpression
|
||||
}
|
||||
|
||||
@@ -432,18 +432,18 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
||||
if (isFunctionType) "($renderedType)." else "$renderedType."
|
||||
} else ""
|
||||
|
||||
val classKind = (callableInfo as? PrimaryConstructorInfo)?.classInfo?.kind
|
||||
val classKind = (callableInfo as? ClassWithPrimaryConstructorInfo)?.classInfo?.kind
|
||||
|
||||
fun renderParamList(): String {
|
||||
val prefix = if (classKind == ClassKind.ANNOTATION_CLASS) "val " else ""
|
||||
val list = callableInfo.parameterInfos.indices.joinToString(", ") { i -> "${prefix}p$i: Any" }
|
||||
return if (callableInfo.parameterInfos.isNotEmpty()
|
||||
|| callableInfo.kind == CallableKind.FUNCTION
|
||||
|| callableInfo.kind == CallableKind.SECONDARY_CONSTRUCTOR) "($list)" else list
|
||||
|| callableInfo.kind == CallableKind.CONSTRUCTOR) "($list)" else list
|
||||
}
|
||||
|
||||
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()
|
||||
CallableKind.PROPERTY -> ""
|
||||
}
|
||||
@@ -459,7 +459,7 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
||||
else if (containingElement is KtClassOrObject
|
||||
&& !(containingElement is KtClass && containingElement.isInterface())
|
||||
&& containingElement.isAncestor(config.originalElement)
|
||||
&& callableInfo.kind != CallableKind.SECONDARY_CONSTRUCTOR) "private "
|
||||
&& callableInfo.kind != CallableKind.CONSTRUCTOR) "private "
|
||||
else if (isExtension) "private "
|
||||
else ""
|
||||
|
||||
@@ -468,9 +468,9 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
||||
}
|
||||
|
||||
val declaration: KtNamedDeclaration = when (callableInfo.kind) {
|
||||
CallableKind.FUNCTION, CallableKind.SECONDARY_CONSTRUCTOR -> {
|
||||
CallableKind.FUNCTION, CallableKind.CONSTRUCTOR -> {
|
||||
val body = when {
|
||||
callableInfo.kind == CallableKind.SECONDARY_CONSTRUCTOR -> ""
|
||||
callableInfo.kind == CallableKind.CONSTRUCTOR -> ""
|
||||
callableInfo.isAbstract -> ""
|
||||
containingElement is KtClass && 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 ""
|
||||
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 {
|
||||
psiFactory.createSecondaryConstructor("${modifiers}constructor$paramList $body") as KtNamedDeclaration
|
||||
}
|
||||
}
|
||||
CallableKind.CLASS_WITH_PRIMARY_CONSTRUCTOR -> {
|
||||
with((callableInfo as PrimaryConstructorInfo).classInfo) {
|
||||
with((callableInfo as ClassWithPrimaryConstructorInfo).classInfo) {
|
||||
val classBody = when (kind) {
|
||||
ClassKind.ANNOTATION_CLASS, ClassKind.ENUM_ENTRY -> ""
|
||||
else -> "{\n\n}"
|
||||
@@ -824,7 +828,7 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
||||
}
|
||||
|
||||
val needStatic = when (callableInfo) {
|
||||
is PrimaryConstructorInfo -> with(callableInfo.classInfo) {
|
||||
is ClassWithPrimaryConstructorInfo -> with(callableInfo.classInfo) {
|
||||
!inner && kind != ClassKind.ENUM_ENTRY && kind != ClassKind.ENUM_CLASS
|
||||
}
|
||||
else -> callableInfo.receiverTypeInfo.staticContextRequired
|
||||
@@ -1052,6 +1056,10 @@ internal fun <D : KtNamedDeclaration> placeDeclarationInContainer(
|
||||
}
|
||||
|
||||
val declarationInPlace = when {
|
||||
declaration is KtPrimaryConstructor -> {
|
||||
(container as KtClass).createPrimaryConstructorIfAbsent().replaced(declaration) as D
|
||||
}
|
||||
|
||||
actualContainer.isAncestor(anchor, true) -> {
|
||||
val insertToBlock = container is KtBlockExpression
|
||||
if (insertToBlock) {
|
||||
|
||||
+6
-5
@@ -161,7 +161,7 @@ class ParameterInfo(
|
||||
enum class CallableKind {
|
||||
FUNCTION,
|
||||
CLASS_WITH_PRIMARY_CONSTRUCTOR,
|
||||
SECONDARY_CONSTRUCTOR,
|
||||
CONSTRUCTOR,
|
||||
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
|
||||
) {
|
||||
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()
|
||||
}
|
||||
|
||||
class SecondaryConstructorInfo(
|
||||
class ConstructorInfo(
|
||||
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) {
|
||||
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()
|
||||
}
|
||||
|
||||
+1
-1
@@ -322,7 +322,7 @@ sealed class CreateCallableFromCallActionFactory<E : KtExpression>(
|
||||
|
||||
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) {
|
||||
CallableKind.FUNCTION -> "function"
|
||||
CallableKind.PROPERTY -> "property"
|
||||
CallableKind.SECONDARY_CONSTRUCTOR -> "secondary constructor"
|
||||
CallableKind.CONSTRUCTOR -> "secondary constructor"
|
||||
else -> throw AssertionError("Unexpected callable info: $it")
|
||||
}
|
||||
append(kind)
|
||||
@@ -185,7 +185,7 @@ abstract class CreateCallableFromUsageFixBase<E : KtElement>(
|
||||
project.executeCommand(text) { callableBuilder.build() }
|
||||
}
|
||||
|
||||
if (callableInfo is SecondaryConstructorInfo) {
|
||||
if (callableInfo is ConstructorInfo) {
|
||||
runBuilder(CallablePlacement.NoReceiver(callableInfo.targetClass))
|
||||
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.quickfix.createFromUsage.callableBuilder.CallableInfo
|
||||
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.refactoring.canRefactor
|
||||
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.quickfix.createFromUsage.callableBuilder.CallableInfo
|
||||
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.psi.KtClass
|
||||
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)
|
||||
else -> throw AssertionError("Unexpected element: " + selectedParent.text)
|
||||
} ?: return@runWriteAction
|
||||
val constructorInfo = PrimaryConstructorInfo(classInfo, expectedTypeInfo)
|
||||
val constructorInfo = ClassWithPrimaryConstructorInfo(classInfo, expectedTypeInfo)
|
||||
val builder = CallableBuilderConfiguration(
|
||||
Collections.singletonList(constructorInfo),
|
||||
element as KtElement,
|
||||
|
||||
Reference in New Issue
Block a user