diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiFactory.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiFactory.kt index 99207c3d726..91edf3324ae 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiFactory.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiFactory.kt @@ -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 = diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertSecondaryConstructorToPrimaryIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertSecondaryConstructorToPrimaryIntention.kt index 4993a757813..49e094a8a00 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertSecondaryConstructorToPrimaryIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/ConvertSecondaryConstructorToPrimaryIntention.kt @@ -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() val initializer = element.extractInitializer(parameterToPropertyMap, context, factory) ?: return diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt index a81bb480456..f1294c81a85 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableBuilder.kt @@ -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 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) { diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableInfo.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableInfo.kt index 9dba0510969..aaaf48b106e 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableInfo.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/callableBuilder/CallableInfo.kt @@ -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, isAbstract: Boolean) = throw UnsupportedOperationException() } -class SecondaryConstructorInfo( +class ConstructorInfo( override val parameterInfos: List, - 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, isAbstract: Boolean) = throw UnsupportedOperationException() } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateCallableFromCallActionFactory.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateCallableFromCallActionFactory.kt index 73d7e0620a8..c10e2a81807 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateCallableFromCallActionFactory.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateCallableFromCallActionFactory.kt @@ -322,7 +322,7 @@ sealed class CreateCallableFromCallActionFactory( val parameters = expression.getParameterInfos() - return SecondaryConstructorInfo(parameters, klass) + return ConstructorInfo(parameters, klass) } } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateCallableFromUsageFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateCallableFromUsageFix.kt index cae18b8faa4..bf1e1d9d369 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateCallableFromUsageFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateCallableFromUsageFix.kt @@ -89,7 +89,7 @@ abstract class CreateCallableFromUsageFixBase( 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( project.executeCommand(text) { callableBuilder.build() } } - if (callableInfo is SecondaryConstructorInfo) { + if (callableInfo is ConstructorInfo) { runBuilder(CallablePlacement.NoReceiver(callableInfo.targetClass)) return } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateConstructorFromDelegationCallActionFactory.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateConstructorFromDelegationCallActionFactory.kt index cf0003aae90..4b5b77db364 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateConstructorFromDelegationCallActionFactory.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateConstructorFromDelegationCallActionFactory.kt @@ -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) } } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateConstructorFromSuperTypeCallActionFactory.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateConstructorFromSuperTypeCallActionFactory.kt index 25648e173ab..98abbc7bab8 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateConstructorFromSuperTypeCallActionFactory.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createCallable/CreateConstructorFromSuperTypeCallActionFactory.kt @@ -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) } } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createClass/CreateClassFromUsageFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createClass/CreateClassFromUsageFix.kt index 43fe9d8ec24..12594b6e749 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createClass/CreateClassFromUsageFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/createFromUsage/createClass/CreateClassFromUsageFix.kt @@ -163,7 +163,7 @@ open class CreateClassFromUsageFix 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,