diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiFactory.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiFactory.kt index e77bd10607d..10b127b2e4e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiFactory.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiFactory.kt @@ -28,6 +28,7 @@ import com.intellij.util.LocalTimeCounter import org.jetbrains.kotlin.analyzer.ModuleInfo import org.jetbrains.kotlin.idea.KotlinFileType import org.jetbrains.kotlin.lexer.KtModifierKeywordToken +import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.ImportPath @@ -211,11 +212,17 @@ class KtPsiFactory(private val project: Project) { return PsiFileFactory.getInstance(project).createFileFromText(fileName, KotlinFileType.INSTANCE, text, LocalTimeCounter.currentTime(), true) as KtFile } - fun createProperty(name: String, type: String?, isVar: Boolean, initializer: String?): KtProperty { - val text = (if (isVar) "var " else "val ") + name + (if (type != null) ":" + type else "") + (if (initializer == null) "" else " = " + initializer) + fun createProperty(modifiers: String?, name: String, type: String?, isVar: Boolean, initializer: String?): KtProperty { + val text = (modifiers.let { "$it "} ?: "") + + (if (isVar) " var " else " val ") + name + + (if (type != null) ":" + type else "") + (if (initializer == null) "" else " = " + initializer) return createProperty(text) } + fun createProperty(name: String, type: String?, isVar: Boolean, initializer: String?): KtProperty { + return createProperty(null, name, type, isVar, initializer) + } + fun createProperty(name: String, type: String?, isVar: Boolean): KtProperty { return createProperty(name, type, isVar, null) } @@ -548,8 +555,14 @@ class KtPsiFactory(private val project: Project) { } class CallableBuilder(private val target: Target) { + + companion object { + val CONSTRUCTOR_NAME = KtTokens.CONSTRUCTOR_KEYWORD.value + } + enum class Target { FUNCTION, + CONSTRUCTOR, READ_ONLY_PROPERTY } @@ -568,7 +581,7 @@ class KtPsiFactory(private val project: Project) { private var state = State.MODIFIERS private fun closeParams() { - if (target == Target.FUNCTION) { + if (target == Target.FUNCTION || target == Target.CONSTRUCTOR) { assert(state == State.FIRST_PARAM || state == State.REST_PARAMS) sb.append(")") } @@ -584,6 +597,7 @@ class KtPsiFactory(private val project: Project) { } val keyword = when (target) { Target.FUNCTION -> "fun" + Target.CONSTRUCTOR -> "" Target.READ_ONLY_PROPERTY -> "val" } sb.append("$keyword ") @@ -592,7 +606,7 @@ class KtPsiFactory(private val project: Project) { } private fun bodyPrefix() = when (target) { - Target.FUNCTION -> "" + Target.FUNCTION, Target.CONSTRUCTOR -> "" Target.READ_ONLY_PROPERTY -> "\nget()" } @@ -604,7 +618,7 @@ class KtPsiFactory(private val project: Project) { return this } - fun typeParams(values: Collection): CallableBuilder { + fun typeParams(values: Collection = emptyList()): CallableBuilder { placeKeyword() if (!values.isEmpty()) { sb.append(values.joinToString(", ", "<", "> ", -1, "")) @@ -622,12 +636,13 @@ class KtPsiFactory(private val project: Project) { return this } - fun name(name: String): CallableBuilder { + fun name(name: String = CONSTRUCTOR_NAME): CallableBuilder { assert(state == State.NAME || state == State.RECEIVER) + assert(name != CONSTRUCTOR_NAME || target == Target.CONSTRUCTOR) sb.append(name) when (target) { - Target.FUNCTION -> { + Target.FUNCTION, Target.CONSTRUCTOR -> { sb.append("(") state = State.FIRST_PARAM } @@ -638,14 +653,17 @@ class KtPsiFactory(private val project: Project) { return this } - fun param(name: String, type: String): CallableBuilder { - assert(target == Target.FUNCTION) + fun param(name: String, type: String, defaultValue: String? = null): CallableBuilder { + assert(target == Target.FUNCTION || target == Target.CONSTRUCTOR) assert(state == State.FIRST_PARAM || state == State.REST_PARAMS) if (state == State.REST_PARAMS) { sb.append(", ") } sb.append(name).append(": ").append(type) + if (defaultValue != null) { + sb.append("= ").append(defaultValue) + } if (state == State.FIRST_PARAM) { state = State.REST_PARAMS } @@ -667,7 +685,7 @@ class KtPsiFactory(private val project: Project) { } fun typeConstraints(values: Collection): CallableBuilder { - assert(state == State.TYPE_CONSTRAINTS) + assert(state == State.TYPE_CONSTRAINTS && target != Target.CONSTRUCTOR) if (!values.isEmpty()) { sb.append(values.joinToString(", ", " where ", "", -1, "")) @@ -677,6 +695,15 @@ class KtPsiFactory(private val project: Project) { return this } + fun superDelegation(argumentList: String): CallableBuilder { + assert(state == State.TYPE_CONSTRAINTS && target == Target.CONSTRUCTOR) + + sb.append(": super").append(argumentList) + state = State.BODY + + return this + } + fun blockBody(body: String): CallableBuilder { assert(state == State.BODY || state == State.TYPE_CONSTRAINTS) diff --git a/idea/resources/intentionDescriptions/ConvertPrimaryConstructorToSecondaryIntention/after.kt.template b/idea/resources/intentionDescriptions/ConvertPrimaryConstructorToSecondaryIntention/after.kt.template new file mode 100644 index 00000000000..19f2ec5b57d --- /dev/null +++ b/idea/resources/intentionDescriptions/ConvertPrimaryConstructorToSecondaryIntention/after.kt.template @@ -0,0 +1,9 @@ +class Foo { + val z = y + + val x: Int + + constructor(x: Int = 4, y: Int) { + this.x = x + } +} \ No newline at end of file diff --git a/idea/resources/intentionDescriptions/ConvertPrimaryConstructorToSecondaryIntention/before.kt.template b/idea/resources/intentionDescriptions/ConvertPrimaryConstructorToSecondaryIntention/before.kt.template new file mode 100644 index 00000000000..a12cfbba09e --- /dev/null +++ b/idea/resources/intentionDescriptions/ConvertPrimaryConstructorToSecondaryIntention/before.kt.template @@ -0,0 +1,3 @@ +class Foo(val x: Int = 4, y: Int) { + val z = y +} \ No newline at end of file diff --git a/idea/resources/intentionDescriptions/ConvertPrimaryConstructorToSecondaryIntention/description.html b/idea/resources/intentionDescriptions/ConvertPrimaryConstructorToSecondaryIntention/description.html new file mode 100644 index 00000000000..772d5720c96 --- /dev/null +++ b/idea/resources/intentionDescriptions/ConvertPrimaryConstructorToSecondaryIntention/description.html @@ -0,0 +1,5 @@ + + +This intention converts primary constructor to secondary one. + + \ No newline at end of file diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index bfb516279c9..94c2a230eab 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -1372,6 +1372,11 @@ Kotlin + + org.jetbrains.kotlin.idea.intentions.ConvertPrimaryConstructorToSecondaryIntention + Kotlin + + ( + KtPrimaryConstructor::class.java, + "Convert to secondary constructor" +) { + override fun isApplicableTo(element: KtPrimaryConstructor, caretOffset: Int) = + element.containingClassOrObject is KtClass && element.valueParameters.all { !it.hasValOrVar() || it.annotationEntries.isEmpty() } + + override fun applyTo(element: KtPrimaryConstructor, editor: Editor?) { + val klass = element.containingClassOrObject as? KtClass ?: return + val factory = KtPsiFactory(klass) + val initializerMap = mutableMapOf() + for (property in klass.getProperties()) { + if (property.typeReference == null) { + SpecifyTypeExplicitlyIntention().applyTo(property, editor) + } + val initializer = property.initializer ?: continue + initializerMap[property] = initializer.text + initializer.delete() + property.equalsToken!!.delete() + } + val constructor = factory.createSecondaryConstructor( + CallableBuilder(CONSTRUCTOR).apply { + element.modifierList?.let { modifier(it.text) } + typeParams() + name() + for (valueParameter in element.valueParameters) { + val annotations = valueParameter.annotationEntries.joinToString(separator = " ") { it.text } + val vararg = if (valueParameter.isVarArg) VARARG_KEYWORD.value else "" + param("$annotations $vararg ${valueParameter.name!!}", + valueParameter.typeReference!!.text, valueParameter.defaultValue?.text) + } + noReturnType() + for (superTypeEntry in klass.getSuperTypeListEntries()) { + if (superTypeEntry is KtSuperTypeCallEntry) { + superDelegation(superTypeEntry.valueArgumentList?.text ?: "") + superTypeEntry.replace(factory.createSuperTypeEntry(superTypeEntry.typeReference!!.text)) + } + } + if (element.valueParameters.firstOrNull { it.hasValOrVar() } != null || initializerMap.isNotEmpty()) { + val valueParameterInitializers = element.valueParameters.filter { it.hasValOrVar() }.joinToString(separator = "\n") { + val name = it.name!! + "this.$name = $name" + } + val classBodyInitializers = klass.declarations.filter { + (it is KtProperty && initializerMap[it] != null) || it is KtAnonymousInitializer + }.joinToString(separator = "\n") { + if (it is KtProperty) { + val name = it.name!! + val text = initializerMap[it] + if (text != null) { + "${THIS_KEYWORD.value}.$name = $text" + } + else { + "" + } + } + else { + ((it as KtAnonymousInitializer).body as? KtBlockExpression)?.statements?.joinToString(separator = "\n") { + it.text + } ?: "" + } + } + blockBody(listOf(valueParameterInitializers, classBodyInitializers) + .filter(String::isNotEmpty).joinToString(separator = "\n")) + } + }.asString() + ) + klass.addDeclarationBefore(constructor, null) + for (valueParameter in element.valueParameters.reversed()) { + if (!valueParameter.hasValOrVar()) continue + val isVararg = valueParameter.hasModifier(VARARG_KEYWORD) + valueParameter.removeModifier(VARARG_KEYWORD) + val typeText = valueParameter.typeReference?.text + val property = factory.createProperty(valueParameter.modifierList?.text, valueParameter.name!!, + if (isVararg && typeText != null) "Array" else typeText, + valueParameter.isMutable, null) + klass.addDeclarationBefore(property, null) + } + for (anonymousInitializer in klass.getAnonymousInitializers()) { + anonymousInitializer.delete() + } + element.delete() + } +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPrimaryConstructorToSecondary/.intention b/idea/testData/intentions/convertPrimaryConstructorToSecondary/.intention new file mode 100644 index 00000000000..ba1ddf6e1c0 --- /dev/null +++ b/idea/testData/intentions/convertPrimaryConstructorToSecondary/.intention @@ -0,0 +1 @@ +org.jetbrains.kotlin.idea.intentions.ConvertPrimaryConstructorToSecondaryIntention diff --git a/idea/testData/intentions/convertPrimaryConstructorToSecondary/annotatedConstructor.kt b/idea/testData/intentions/convertPrimaryConstructorToSecondary/annotatedConstructor.kt new file mode 100644 index 00000000000..504ff9bdf72 --- /dev/null +++ b/idea/testData/intentions/convertPrimaryConstructorToSecondary/annotatedConstructor.kt @@ -0,0 +1,3 @@ +annotation class Ann(val t: String) + +class Annotated @Ann("42") constructor() \ No newline at end of file diff --git a/idea/testData/intentions/convertPrimaryConstructorToSecondary/annotatedConstructor.kt.after b/idea/testData/intentions/convertPrimaryConstructorToSecondary/annotatedConstructor.kt.after new file mode 100644 index 00000000000..f8a1e0e8673 --- /dev/null +++ b/idea/testData/intentions/convertPrimaryConstructorToSecondary/annotatedConstructor.kt.after @@ -0,0 +1,5 @@ +annotation class Ann(val t: String) + +class Annotated { + @Ann("42") constructor() +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPrimaryConstructorToSecondary/annotatedParam.kt b/idea/testData/intentions/convertPrimaryConstructorToSecondary/annotatedParam.kt new file mode 100644 index 00000000000..98adf84b206 --- /dev/null +++ b/idea/testData/intentions/convertPrimaryConstructorToSecondary/annotatedParam.kt @@ -0,0 +1,5 @@ +annotation class Ann + +class AnnotatedParam(@Ann x: Double) { + val y = x +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPrimaryConstructorToSecondary/annotatedParam.kt.after b/idea/testData/intentions/convertPrimaryConstructorToSecondary/annotatedParam.kt.after new file mode 100644 index 00000000000..85e387c28ff --- /dev/null +++ b/idea/testData/intentions/convertPrimaryConstructorToSecondary/annotatedParam.kt.after @@ -0,0 +1,9 @@ +annotation class Ann + +class AnnotatedParam { + constructor(@Ann x: Double) { + this.y = x + } + + val y: Double +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPrimaryConstructorToSecondary/annotatedProperty.kt b/idea/testData/intentions/convertPrimaryConstructorToSecondary/annotatedProperty.kt new file mode 100644 index 00000000000..60767b9b47a --- /dev/null +++ b/idea/testData/intentions/convertPrimaryConstructorToSecondary/annotatedProperty.kt @@ -0,0 +1,5 @@ +// IS_APPLICABLE: false + +annotation class Ann + +class AnnotatedParam(val v: Double, @Ann val x: Int, var s: String) \ No newline at end of file diff --git a/idea/testData/intentions/convertPrimaryConstructorToSecondary/defaultValueChain.kt b/idea/testData/intentions/convertPrimaryConstructorToSecondary/defaultValueChain.kt new file mode 100644 index 00000000000..461990dde32 --- /dev/null +++ b/idea/testData/intentions/convertPrimaryConstructorToSecondary/defaultValueChain.kt @@ -0,0 +1 @@ +class DefaultValueChain(val x1: Int, x2: Int = x1, val x3: Int = x2, x4: Int = x3, val x5: Int = x4) \ No newline at end of file diff --git a/idea/testData/intentions/convertPrimaryConstructorToSecondary/defaultValueChain.kt.after b/idea/testData/intentions/convertPrimaryConstructorToSecondary/defaultValueChain.kt.after new file mode 100644 index 00000000000..d1e1a99b34a --- /dev/null +++ b/idea/testData/intentions/convertPrimaryConstructorToSecondary/defaultValueChain.kt.after @@ -0,0 +1,11 @@ +class DefaultValueChain { + val x1: Int + val x3: Int + val x5: Int + + constructor(x1: Int, x2: Int = x1, x3: Int = x2, x4: Int = x3, x5: Int = x4) { + this.x1 = x1 + this.x3 = x3 + this.x5 = x5 + } +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPrimaryConstructorToSecondary/initAndParams.kt b/idea/testData/intentions/convertPrimaryConstructorToSecondary/initAndParams.kt new file mode 100644 index 00000000000..df9160c35c1 --- /dev/null +++ b/idea/testData/intentions/convertPrimaryConstructorToSecondary/initAndParams.kt @@ -0,0 +1,13 @@ +class InitAndParams(x: Int, z: Int) { + val y = x + + val w: Int + + init { + w = foo(y) + } + + fun foo(arg: Int) = arg + + val v = w + z +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPrimaryConstructorToSecondary/initAndParams.kt.after b/idea/testData/intentions/convertPrimaryConstructorToSecondary/initAndParams.kt.after new file mode 100644 index 00000000000..9da72b2a300 --- /dev/null +++ b/idea/testData/intentions/convertPrimaryConstructorToSecondary/initAndParams.kt.after @@ -0,0 +1,15 @@ +class InitAndParams { + constructor(x: Int, z: Int) { + this.y = x + w = foo(y) + this.v = w + z + } + + val y: Int + + val w: Int + + fun foo(arg: Int) = arg + + val v: Int +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPrimaryConstructorToSecondary/paramsAndProperties.kt b/idea/testData/intentions/convertPrimaryConstructorToSecondary/paramsAndProperties.kt new file mode 100644 index 00000000000..d811482548d --- /dev/null +++ b/idea/testData/intentions/convertPrimaryConstructorToSecondary/paramsAndProperties.kt @@ -0,0 +1,7 @@ +class ParamAndProperties(x: Int, val y: Int, z: Int, val w: Int) { + val r = x + z + + val s = r + y + + val t = s + w +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPrimaryConstructorToSecondary/paramsAndProperties.kt.after b/idea/testData/intentions/convertPrimaryConstructorToSecondary/paramsAndProperties.kt.after new file mode 100644 index 00000000000..096b82598e0 --- /dev/null +++ b/idea/testData/intentions/convertPrimaryConstructorToSecondary/paramsAndProperties.kt.after @@ -0,0 +1,18 @@ +class ParamAndProperties { + val y: Int + val w: Int + + constructor(x: Int, y: Int, z: Int, w: Int) { + this.y = y + this.w = w + this.r = x + z + this.s = r + y + this.t = s + w + } + + val r: Int + + val s: Int + + val t: Int +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPrimaryConstructorToSecondary/protectedConstructor.kt b/idea/testData/intentions/convertPrimaryConstructorToSecondary/protectedConstructor.kt new file mode 100644 index 00000000000..05e1ae61fab --- /dev/null +++ b/idea/testData/intentions/convertPrimaryConstructorToSecondary/protectedConstructor.kt @@ -0,0 +1 @@ +class Protected protected constructor(internal var s: String) \ No newline at end of file diff --git a/idea/testData/intentions/convertPrimaryConstructorToSecondary/protectedConstructor.kt.after b/idea/testData/intentions/convertPrimaryConstructorToSecondary/protectedConstructor.kt.after new file mode 100644 index 00000000000..7366ec90325 --- /dev/null +++ b/idea/testData/intentions/convertPrimaryConstructorToSecondary/protectedConstructor.kt.after @@ -0,0 +1,7 @@ +class Protected { + internal var s: String + + protected constructor(s: String) { + this.s = s + } +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPrimaryConstructorToSecondary/simple.kt b/idea/testData/intentions/convertPrimaryConstructorToSecondary/simple.kt new file mode 100644 index 00000000000..47cc21cdc56 --- /dev/null +++ b/idea/testData/intentions/convertPrimaryConstructorToSecondary/simple.kt @@ -0,0 +1 @@ +class My() \ No newline at end of file diff --git a/idea/testData/intentions/convertPrimaryConstructorToSecondary/simple.kt.after b/idea/testData/intentions/convertPrimaryConstructorToSecondary/simple.kt.after new file mode 100644 index 00000000000..cd96d514f66 --- /dev/null +++ b/idea/testData/intentions/convertPrimaryConstructorToSecondary/simple.kt.after @@ -0,0 +1,3 @@ +class My { + constructor() +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPrimaryConstructorToSecondary/useParam.kt b/idea/testData/intentions/convertPrimaryConstructorToSecondary/useParam.kt new file mode 100644 index 00000000000..93d0866198c --- /dev/null +++ b/idea/testData/intentions/convertPrimaryConstructorToSecondary/useParam.kt @@ -0,0 +1,3 @@ +class UseParam(x: Int) { + val y = x +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPrimaryConstructorToSecondary/useParam.kt.after b/idea/testData/intentions/convertPrimaryConstructorToSecondary/useParam.kt.after new file mode 100644 index 00000000000..f7be34ca042 --- /dev/null +++ b/idea/testData/intentions/convertPrimaryConstructorToSecondary/useParam.kt.after @@ -0,0 +1,7 @@ +class UseParam { + constructor(x: Int) { + this.y = x + } + + val y: Int +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPrimaryConstructorToSecondary/useParamChain.kt b/idea/testData/intentions/convertPrimaryConstructorToSecondary/useParamChain.kt new file mode 100644 index 00000000000..af6a8f16356 --- /dev/null +++ b/idea/testData/intentions/convertPrimaryConstructorToSecondary/useParamChain.kt @@ -0,0 +1,5 @@ +class UseParam(x: Int) { + val y = x + + val z = 2 * y +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPrimaryConstructorToSecondary/useParamChain.kt.after b/idea/testData/intentions/convertPrimaryConstructorToSecondary/useParamChain.kt.after new file mode 100644 index 00000000000..0897d91bcd7 --- /dev/null +++ b/idea/testData/intentions/convertPrimaryConstructorToSecondary/useParamChain.kt.after @@ -0,0 +1,10 @@ +class UseParam { + constructor(x: Int) { + this.y = x + this.z = 2 * y + } + + val y: Int + + val z: Int +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPrimaryConstructorToSecondary/vararg.kt b/idea/testData/intentions/convertPrimaryConstructorToSecondary/vararg.kt new file mode 100644 index 00000000000..ba2e672ec7a --- /dev/null +++ b/idea/testData/intentions/convertPrimaryConstructorToSecondary/vararg.kt @@ -0,0 +1,5 @@ +// WITH_RUNTIME + +class VarArg(vararg x: String) { + val strList = x.toList() +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPrimaryConstructorToSecondary/vararg.kt.after b/idea/testData/intentions/convertPrimaryConstructorToSecondary/vararg.kt.after new file mode 100644 index 00000000000..cc8ab094f0f --- /dev/null +++ b/idea/testData/intentions/convertPrimaryConstructorToSecondary/vararg.kt.after @@ -0,0 +1,9 @@ +// WITH_RUNTIME + +class VarArg { + constructor(vararg x: String) { + this.strList = x.toList() + } + + val strList: List +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPrimaryConstructorToSecondary/varargVal.kt b/idea/testData/intentions/convertPrimaryConstructorToSecondary/varargVal.kt new file mode 100644 index 00000000000..75d30b84013 --- /dev/null +++ b/idea/testData/intentions/convertPrimaryConstructorToSecondary/varargVal.kt @@ -0,0 +1,3 @@ +// WITH_RUNTIME + +class VarargVal(vararg val param: String) \ No newline at end of file diff --git a/idea/testData/intentions/convertPrimaryConstructorToSecondary/varargVal.kt.after b/idea/testData/intentions/convertPrimaryConstructorToSecondary/varargVal.kt.after new file mode 100644 index 00000000000..e29b585f539 --- /dev/null +++ b/idea/testData/intentions/convertPrimaryConstructorToSecondary/varargVal.kt.after @@ -0,0 +1,9 @@ +// WITH_RUNTIME + +class VarargVal { + val param: Array + + constructor(vararg param: String) { + this.param = param + } +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPrimaryConstructorToSecondary/withBaseClass.kt b/idea/testData/intentions/convertPrimaryConstructorToSecondary/withBaseClass.kt new file mode 100644 index 00000000000..bea2bc4bc03 --- /dev/null +++ b/idea/testData/intentions/convertPrimaryConstructorToSecondary/withBaseClass.kt @@ -0,0 +1,5 @@ +abstract class Base(val x: Int) + +class Derived(x: Int) : Base(x) { + val y = 2 * x +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPrimaryConstructorToSecondary/withBaseClass.kt.after b/idea/testData/intentions/convertPrimaryConstructorToSecondary/withBaseClass.kt.after new file mode 100644 index 00000000000..f3425064c6b --- /dev/null +++ b/idea/testData/intentions/convertPrimaryConstructorToSecondary/withBaseClass.kt.after @@ -0,0 +1,9 @@ +abstract class Base(val x: Int) + +class Derived : Base { + constructor(x: Int) : super(x) { + this.y = 2 * x + } + + val y: Int +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPrimaryConstructorToSecondary/withMultipleInheritance.kt b/idea/testData/intentions/convertPrimaryConstructorToSecondary/withMultipleInheritance.kt new file mode 100644 index 00000000000..0dbc114aa29 --- /dev/null +++ b/idea/testData/intentions/convertPrimaryConstructorToSecondary/withMultipleInheritance.kt @@ -0,0 +1,15 @@ +interface A { + val s: String +} + +interface B { + val x: Int +} + +abstract class C(open val d: Double) + +class D(open val y: Int, override val d: Double) : A, C(d), B { + override val s = "$y -> $d" + + override val x = y * y +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPrimaryConstructorToSecondary/withMultipleInheritance.kt.after b/idea/testData/intentions/convertPrimaryConstructorToSecondary/withMultipleInheritance.kt.after new file mode 100644 index 00000000000..f1c5028638e --- /dev/null +++ b/idea/testData/intentions/convertPrimaryConstructorToSecondary/withMultipleInheritance.kt.after @@ -0,0 +1,25 @@ +interface A { + val s: String +} + +interface B { + val x: Int +} + +abstract class C(open val d: Double) + +class D : A, C, B { + open val y: Int + override val d: Double + + constructor(y: Int, d: Double) : super(d) { + this.y = y + this.d = d + this.s = "$y -> $d" + this.x = y * y + } + + override val s: String + + override val x: Int +} \ No newline at end of file diff --git a/idea/testData/intentions/convertPrimaryConstructorToSecondary/withProperties.kt b/idea/testData/intentions/convertPrimaryConstructorToSecondary/withProperties.kt new file mode 100644 index 00000000000..5f579e3a16f --- /dev/null +++ b/idea/testData/intentions/convertPrimaryConstructorToSecondary/withProperties.kt @@ -0,0 +1 @@ +class WithProperties(val x: Int, val y: Int = 7, private val z: Int = 13) \ No newline at end of file diff --git a/idea/testData/intentions/convertPrimaryConstructorToSecondary/withProperties.kt.after b/idea/testData/intentions/convertPrimaryConstructorToSecondary/withProperties.kt.after new file mode 100644 index 00000000000..f89813bf5b2 --- /dev/null +++ b/idea/testData/intentions/convertPrimaryConstructorToSecondary/withProperties.kt.after @@ -0,0 +1,11 @@ +class WithProperties { + val x: Int + val y: Int + private val z: Int + + constructor(x: Int, y: Int = 7, z: Int = 13) { + this.x = x + this.y = y + this.z = z + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/addTypeAnnotationToValueParameter/noDefaultValue.kt b/idea/testData/quickfix/addTypeAnnotationToValueParameter/noDefaultValue.kt index b62e12fe2bc..8800dc34950 100644 --- a/idea/testData/quickfix/addTypeAnnotationToValueParameter/noDefaultValue.kt +++ b/idea/testData/quickfix/addTypeAnnotationToValueParameter/noDefaultValue.kt @@ -1,5 +1,6 @@ // "class org.jetbrains.kotlin.idea.quickfix.AddTypeAnnotationToValueParameterFix" "false" // ERROR: A type annotation is required on a value parameter // ACTION: Create test +// ACTION: Convert to secondary constructor class Foo(val bar) \ No newline at end of file diff --git a/idea/testData/quickfix/variables/removeValVarFromParameter/constructorParameter.kt b/idea/testData/quickfix/variables/removeValVarFromParameter/constructorParameter.kt index 52236b5b496..6ec2e29fb32 100644 --- a/idea/testData/quickfix/variables/removeValVarFromParameter/constructorParameter.kt +++ b/idea/testData/quickfix/variables/removeValVarFromParameter/constructorParameter.kt @@ -3,5 +3,6 @@ // ACTION: Make private // ACTION: Make protected // ACTION: Create test +// ACTION: Convert to secondary constructor class C(val x: String) { } \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java index f668d9ddb7c..f4ea5a93dc1 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java @@ -4358,6 +4358,105 @@ public class IntentionTestGenerated extends AbstractIntentionTest { } } + @TestMetadata("idea/testData/intentions/convertPrimaryConstructorToSecondary") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class ConvertPrimaryConstructorToSecondary extends AbstractIntentionTest { + public void testAllFilesPresentInConvertPrimaryConstructorToSecondary() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/convertPrimaryConstructorToSecondary"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true); + } + + @TestMetadata("annotatedConstructor.kt") + public void testAnnotatedConstructor() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertPrimaryConstructorToSecondary/annotatedConstructor.kt"); + doTest(fileName); + } + + @TestMetadata("annotatedParam.kt") + public void testAnnotatedParam() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertPrimaryConstructorToSecondary/annotatedParam.kt"); + doTest(fileName); + } + + @TestMetadata("annotatedProperty.kt") + public void testAnnotatedProperty() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertPrimaryConstructorToSecondary/annotatedProperty.kt"); + doTest(fileName); + } + + @TestMetadata("defaultValueChain.kt") + public void testDefaultValueChain() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertPrimaryConstructorToSecondary/defaultValueChain.kt"); + doTest(fileName); + } + + @TestMetadata("initAndParams.kt") + public void testInitAndParams() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertPrimaryConstructorToSecondary/initAndParams.kt"); + doTest(fileName); + } + + @TestMetadata("paramsAndProperties.kt") + public void testParamsAndProperties() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertPrimaryConstructorToSecondary/paramsAndProperties.kt"); + doTest(fileName); + } + + @TestMetadata("protectedConstructor.kt") + public void testProtectedConstructor() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertPrimaryConstructorToSecondary/protectedConstructor.kt"); + doTest(fileName); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertPrimaryConstructorToSecondary/simple.kt"); + doTest(fileName); + } + + @TestMetadata("useParam.kt") + public void testUseParam() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertPrimaryConstructorToSecondary/useParam.kt"); + doTest(fileName); + } + + @TestMetadata("useParamChain.kt") + public void testUseParamChain() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertPrimaryConstructorToSecondary/useParamChain.kt"); + doTest(fileName); + } + + @TestMetadata("vararg.kt") + public void testVararg() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertPrimaryConstructorToSecondary/vararg.kt"); + doTest(fileName); + } + + @TestMetadata("varargVal.kt") + public void testVarargVal() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertPrimaryConstructorToSecondary/varargVal.kt"); + doTest(fileName); + } + + @TestMetadata("withBaseClass.kt") + public void testWithBaseClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertPrimaryConstructorToSecondary/withBaseClass.kt"); + doTest(fileName); + } + + @TestMetadata("withMultipleInheritance.kt") + public void testWithMultipleInheritance() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertPrimaryConstructorToSecondary/withMultipleInheritance.kt"); + doTest(fileName); + } + + @TestMetadata("withProperties.kt") + public void testWithProperties() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/convertPrimaryConstructorToSecondary/withProperties.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/testData/intentions/convertPropertyInitializerToGetter") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)