mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[kotlin] k2: port generate secondary constructor action
^KTIJ-30776 fixed GitOrigin-RevId: 9491460bfbaf93586145c87537a4a8b81398c8df
This commit is contained in:
committed by
intellij-monorepo-bot
parent
2d3ae1afee
commit
18a6a9d5a3
+2
@@ -244,6 +244,8 @@
|
||||
</extensions>
|
||||
<actions>
|
||||
<group id="KotlinGenerateGroup">
|
||||
<action id="KotlinGenerateSecondaryConstructor"
|
||||
class="org.jetbrains.kotlin.idea.k2.codeinsight.generate.KotlinGenerateSecondaryConstructorAction"/>
|
||||
<action id="KotlinGenerateEqualsAndHashCode"
|
||||
class="org.jetbrains.kotlin.idea.k2.codeinsight.generate.KotlinGenerateEqualsAndHashcodeAction"/>
|
||||
<action id="KotlinGenerateToString"
|
||||
|
||||
+246
@@ -0,0 +1,246 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
|
||||
|
||||
package org.jetbrains.kotlin.idea.k2.codeinsight.generate
|
||||
|
||||
import com.intellij.codeInsight.generation.ClassMember
|
||||
import com.intellij.codeInsight.generation.PsiElementMemberChooserObject
|
||||
import com.intellij.ide.util.MemberChooser
|
||||
import com.intellij.java.JavaBundle
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiMethod
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil
|
||||
import org.jetbrains.kotlin.analysis.api.KaExperimentalApi
|
||||
import org.jetbrains.kotlin.analysis.api.KaSession
|
||||
import org.jetbrains.kotlin.analysis.api.components.KaDiagnosticCheckerFilter
|
||||
import org.jetbrains.kotlin.analysis.api.fir.diagnostics.KaFirDiagnostic
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KaClassKind
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KaClassSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.types.KaType
|
||||
import org.jetbrains.kotlin.analysis.api.types.symbol
|
||||
import org.jetbrains.kotlin.idea.base.analysis.api.utils.analyzeInModalWindow
|
||||
import org.jetbrains.kotlin.idea.base.codeInsight.KotlinNameSuggester
|
||||
import org.jetbrains.kotlin.idea.base.codeInsight.KotlinPsiElementMemberChooserObject
|
||||
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
|
||||
import org.jetbrains.kotlin.idea.core.*
|
||||
import org.jetbrains.kotlin.idea.core.CollectingNameValidator
|
||||
import org.jetbrains.kotlin.idea.refactoring.addElement
|
||||
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
|
||||
import org.jetbrains.kotlin.idea.util.application.isUnitTestMode
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.quoteIfNeeded
|
||||
import org.jetbrains.kotlin.psi.psiUtil.siblings
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.lastIsInstanceOrNull
|
||||
|
||||
class KotlinGenerateSecondaryConstructorAction : KotlinGenerateMemberActionBase<KotlinGenerateSecondaryConstructorAction.Info>() {
|
||||
class Info(
|
||||
val propertiesToInitialize: List<KotlinPsiElementMemberChooserObject>,
|
||||
val superConstructors: List<ClassMember>,
|
||||
val klass: KtClass
|
||||
)
|
||||
|
||||
override fun isValidForClass(targetClass: KtClassOrObject): Boolean {
|
||||
return targetClass is KtClass
|
||||
&& targetClass !is KtEnumEntry
|
||||
&& !targetClass.isInterface()
|
||||
&& !targetClass.isAnnotation()
|
||||
&& !targetClass.hasExplicitPrimaryConstructor()
|
||||
}
|
||||
|
||||
private fun shouldPreselect(element: PsiElement) = element is KtProperty && !element.isVar
|
||||
|
||||
context(KaSession)
|
||||
@OptIn(KaExperimentalApi::class)
|
||||
private fun chooseSuperConstructors(classSymbol: KaClassSymbol): List<ClassMember> {
|
||||
val superClassSymbol = getSuperClassSymbolNoAny(classSymbol) ?: return emptyList()
|
||||
val candidates = superClassSymbol.declaredMemberScope.constructors
|
||||
.filter { it.isVisibleInClass(classSymbol) }
|
||||
.mapNotNull { constructorSymbol ->
|
||||
constructorSymbol.psi?.let { KotlinPsiElementMemberChooserObject.getMemberChooserObject(it) } as? ClassMember
|
||||
}.toList()
|
||||
return candidates
|
||||
}
|
||||
|
||||
context(KaSession)
|
||||
private fun getSuperClassSymbolNoAny(classSymbol: KaClassSymbol): KaClassSymbol? =
|
||||
classSymbol.superTypes.mapNotNull { it.symbol as? KaClassSymbol }.find { superClassSymbol ->
|
||||
superClassSymbol.classKind == KaClassKind.CLASS && superClassSymbol.classId != StandardClassIds.Any
|
||||
}
|
||||
|
||||
context(KaSession)
|
||||
@OptIn(KaExperimentalApi::class)
|
||||
private fun KtProperty.isPropertyNotInitialized(): Boolean {
|
||||
return containingKtFile.collectDiagnostics(KaDiagnosticCheckerFilter.ONLY_COMMON_CHECKERS)
|
||||
.filter { it.psi == this@isPropertyNotInitialized }
|
||||
.any { it is KaFirDiagnostic.MustBeInitializedOrBeAbstract }
|
||||
}
|
||||
|
||||
context(KaSession)
|
||||
private fun choosePropertiesToInitialize(klass: KtClassOrObject): List<KotlinPsiElementMemberChooserObject> {
|
||||
return klass.declarations
|
||||
.asSequence()
|
||||
.filterIsInstance<KtProperty>()
|
||||
.filter { it.isVar || it.isPropertyNotInitialized() }
|
||||
.map { KotlinPsiElementMemberChooserObject.getKotlinMemberChooserObject(it) }
|
||||
.toList()
|
||||
}
|
||||
|
||||
override fun prepareMembersInfo(klass: KtClassOrObject, project: Project, editor: Editor): Info? {
|
||||
if (klass !is KtClass) return null
|
||||
val preInfo = analyzeInModalWindow(klass, KotlinBundle.message("fix.change.signature.prepare")) {
|
||||
val classSymbol = klass.symbol as? KaClassSymbol ?: return@analyzeInModalWindow null
|
||||
val superConstructors = chooseSuperConstructors(classSymbol)
|
||||
val propertiesToInitialize = choosePropertiesToInitialize(klass)
|
||||
return@analyzeInModalWindow Info(propertiesToInitialize, superConstructors, klass)
|
||||
} ?: return null
|
||||
|
||||
val superConstructors = preInfo.superConstructors
|
||||
val chosenConstructors = if (isUnitTestMode() || superConstructors.size <= 1) {
|
||||
superConstructors
|
||||
}
|
||||
else {
|
||||
val chooser = MemberChooser(superConstructors.toTypedArray(), false, true, klass.project)
|
||||
chooser.title = JavaBundle.message("generate.constructor.super.constructor.chooser.title")
|
||||
chooser.setCopyJavadocVisible(false)
|
||||
chooser.show()
|
||||
|
||||
chooser.selectedElements
|
||||
} ?: return null
|
||||
|
||||
val properties = preInfo.propertiesToInitialize
|
||||
val chosenProperties = if (isUnitTestMode() || properties.isEmpty()) {
|
||||
properties
|
||||
}
|
||||
else {
|
||||
with(MemberChooser(properties.toTypedArray(), true, true, klass.project, false, null)) {
|
||||
title = KotlinBundle.message("action.generate.secondary.constructor.choose.properties")
|
||||
setCopyJavadocVisible(false)
|
||||
selectElements(properties.filter { shouldPreselect(it.element) }.toTypedArray())
|
||||
show()
|
||||
|
||||
selectedElements
|
||||
}
|
||||
} ?: return null
|
||||
return Info(chosenProperties, chosenConstructors, preInfo.klass)
|
||||
}
|
||||
|
||||
override fun generateMembers(project: Project, editor: Editor, info: Info): List<KtDeclaration> {
|
||||
val targetClass = info.klass
|
||||
|
||||
fun Info.findAnchor(): PsiElement? {
|
||||
targetClass.declarations.lastIsInstanceOrNull<KtSecondaryConstructor>()?.let { return it }
|
||||
val lastPropertyToInitialize = propertiesToInitialize.lastOrNull()?.psiElement
|
||||
val declarationsAfter =
|
||||
lastPropertyToInitialize?.siblings()?.filterIsInstance<KtDeclaration>() ?: targetClass.declarations.asSequence()
|
||||
val firstNonProperty = declarationsAfter.firstOrNull { it !is KtProperty } ?: return null
|
||||
return firstNonProperty.siblings(forward = false).firstIsInstanceOrNull<KtProperty>() ?: targetClass.getOrCreateBody().lBrace
|
||||
}
|
||||
|
||||
return with(info) {
|
||||
val prototypes =
|
||||
analyzeInModalWindow(klass, KotlinBundle.message("fix.change.signature.prepare")) {
|
||||
if (superConstructors.isNotEmpty()) {
|
||||
superConstructors.mapNotNull { generateConstructor(klass, propertiesToInitialize.mapNotNull { it.psiElement as? KtProperty }, it) }
|
||||
} else {
|
||||
listOfNotNull(generateConstructor(klass, propertiesToInitialize.mapNotNull { it.psiElement as? KtProperty }, null))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (prototypes.isEmpty()) {
|
||||
val errorText = KotlinBundle.message("action.generate.secondary.constructor.error.already.exists")
|
||||
CommonRefactoringUtil.showErrorHint(targetClass.project, editor, errorText, commandName, null)
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
var constructors: List<KtSecondaryConstructor>? = null
|
||||
project.executeWriteCommand(commandName) {
|
||||
constructors = insertMembersAfterAndReformat(editor, targetClass, prototypes, findAnchor())
|
||||
}
|
||||
return constructors ?: emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
context(KaSession)
|
||||
@OptIn(KaExperimentalApi::class)
|
||||
private fun generateConstructor(
|
||||
klass: KtClass,
|
||||
propertiesToInitialize: List<KtProperty>,
|
||||
superConstructor: ClassMember?
|
||||
): KtSecondaryConstructor? {
|
||||
|
||||
val classSymbol = klass.symbol as? KaClassSymbol ?: return null
|
||||
|
||||
val superConstructorPsi = (superConstructor as? PsiElementMemberChooserObject)?.psiElement
|
||||
val superConstructorSymbol = when (superConstructorPsi) {
|
||||
is KtConstructor<*> -> superConstructorPsi.symbol
|
||||
is PsiMethod -> superConstructorPsi.containingClass?.namedClassSymbol?.declaredMemberScope?.constructors?.find { it.psi == superConstructorPsi }
|
||||
else -> null
|
||||
}
|
||||
|
||||
val constructorParamTypes = propertiesToInitialize.map { it.returnType } +
|
||||
(superConstructorSymbol?.valueParameters?.map { it.returnType } ?: emptyList())
|
||||
|
||||
fun equalTypes(types1: Collection<KaType>, types2: Collection<KaType>): Boolean {
|
||||
return types1.size == types2.size && types1.zip(types2).all { it.first.semanticallyEquals(it.second) }
|
||||
}
|
||||
|
||||
if (classSymbol.declaredMemberScope.constructors.any { constructorSymbol ->
|
||||
constructorSymbol.psi is KtConstructor<*> &&
|
||||
equalTypes(constructorSymbol.valueParameters.map { it.returnType }, constructorParamTypes)
|
||||
}
|
||||
) return null
|
||||
|
||||
val psiFactory = KtPsiFactory(klass.project)
|
||||
|
||||
val validator = CollectingNameValidator()
|
||||
|
||||
val constructor = psiFactory.createSecondaryConstructor("constructor()")
|
||||
val parameterList = constructor.valueParameterList!!
|
||||
|
||||
if (superConstructorSymbol != null) {
|
||||
val superClassSymbol = superConstructorSymbol.containingSymbol as? KaClassSymbol ?: return null
|
||||
val substitutor = createInheritanceTypeSubstitutor(classSymbol, superClassSymbol) ?: return null
|
||||
|
||||
val delegationCallArguments = ArrayList<String>()
|
||||
for (parameter in superConstructorSymbol.valueParameters) {
|
||||
val isVararg = parameter.isVararg
|
||||
val paramName = suggestSafeNameByName(parameter.name.asString(), validator)
|
||||
val typeToUse = parameter.returnType
|
||||
val paramType = substitutor.substitute(typeToUse).render(position = Variance.IN_VARIANCE)
|
||||
val modifiers = if (isVararg) "vararg " else ""
|
||||
|
||||
parameterList.addParameter(psiFactory.createParameter("$modifiers$paramName: $paramType"))
|
||||
delegationCallArguments.add(if (isVararg) "*$paramName" else paramName)
|
||||
}
|
||||
|
||||
val delegationCall =
|
||||
psiFactory.creareDelegatedSuperTypeEntry(delegationCallArguments.joinToString(prefix = "super(", postfix = ")"))
|
||||
constructor.replaceImplicitDelegationCallWithExplicit(false).replace(delegationCall)
|
||||
}
|
||||
|
||||
if (propertiesToInitialize.isNotEmpty()) {
|
||||
val body = psiFactory.createEmptyBody()
|
||||
for (property in propertiesToInitialize) {
|
||||
val propertyName = property.name ?: continue
|
||||
val paramName = suggestSafeNameByName(propertyName, validator)
|
||||
val paramType = property.returnType.render(position = Variance.IN_VARIANCE)
|
||||
|
||||
parameterList.addParameter(psiFactory.createParameter("$paramName: $paramType"))
|
||||
body.addElement(psiFactory.createExpression("this.${propertyName.quoteIfNeeded()} = $paramName"), true)
|
||||
}
|
||||
|
||||
constructor.add(body)
|
||||
}
|
||||
|
||||
return constructor
|
||||
}
|
||||
|
||||
private fun suggestSafeNameByName(originalName: String, validator: CollectingNameValidator): String =
|
||||
KotlinNameSuggester.suggestNameByName(originalName, validator).quoteIfNeeded()
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.kotlin.idea.k2.generate
|
||||
|
||||
import com.intellij.codeInsight.actions.CodeInsightAction
|
||||
import com.intellij.openapi.actionSystem.AnAction
|
||||
import com.intellij.openapi.actionSystem.Presentation
|
||||
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
|
||||
import org.jetbrains.kotlin.idea.base.test.InTextDirectivesUtils
|
||||
import org.jetbrains.kotlin.idea.codeInsight.generate.AbstractCodeInsightActionTest
|
||||
import org.jetbrains.kotlin.idea.k2.codeinsight.generate.KotlinGenerateSecondaryConstructorAction
|
||||
import org.jetbrains.kotlin.idea.k2.codeinsight.generate.KotlinGenerateToStringAction
|
||||
import org.jetbrains.kotlin.idea.k2.codeinsight.generate.KotlinToStringTemplatesManager
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
|
||||
abstract class AbstractFirGenerateSecondaryConstructorActionTest : AbstractCodeInsightActionTest() {
|
||||
override fun createAction(fileText: String): CodeInsightAction {
|
||||
return KotlinGenerateSecondaryConstructorAction()
|
||||
}
|
||||
}
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
|
||||
package org.jetbrains.kotlin.idea.k2.generate;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.idea.base.plugin.KotlinPluginMode;
|
||||
import org.jetbrains.kotlin.idea.base.test.TestRoot;
|
||||
import org.jetbrains.kotlin.idea.test.JUnit3RunnerWithInners;
|
||||
import org.jetbrains.kotlin.idea.test.KotlinTestUtils;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/**
|
||||
* This class is generated by {@link org.jetbrains.kotlin.testGenerator.generator.TestGenerator}.
|
||||
* DO NOT MODIFY MANUALLY.
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
@TestRoot("code-insight/kotlin.code-insight.k2")
|
||||
@TestDataPath("$CONTENT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@TestMetadata("../../idea/tests/testData/codeInsight/generate/secondaryConstructors")
|
||||
public class FirGenerateSecondaryConstructorActionTestGenerated extends AbstractFirGenerateSecondaryConstructorActionTest {
|
||||
@java.lang.Override
|
||||
@org.jetbrains.annotations.NotNull
|
||||
public final KotlinPluginMode getPluginMode() {
|
||||
return KotlinPluginMode.K2;
|
||||
}
|
||||
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||
}
|
||||
|
||||
@TestMetadata("empty.kt")
|
||||
public void testEmpty() throws Exception {
|
||||
runTest("../../idea/tests/testData/codeInsight/generate/secondaryConstructors/empty.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("emptyExists.kt")
|
||||
public void testEmptyExists() throws Exception {
|
||||
runTest("../../idea/tests/testData/codeInsight/generate/secondaryConstructors/emptyExists.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("javaSupers.kt")
|
||||
public void testJavaSupers() throws Exception {
|
||||
runTest("../../idea/tests/testData/codeInsight/generate/secondaryConstructors/javaSupers.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("javaSupersWithGenerics.kt")
|
||||
public void testJavaSupersWithGenerics() throws Exception {
|
||||
runTest("../../idea/tests/testData/codeInsight/generate/secondaryConstructors/javaSupersWithGenerics.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("javaSupersWithKeywords.kt")
|
||||
public void testJavaSupersWithKeywords() throws Exception {
|
||||
runTest("../../idea/tests/testData/codeInsight/generate/secondaryConstructors/javaSupersWithKeywords.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("primaryExists.kt")
|
||||
public void testPrimaryExists() throws Exception {
|
||||
runTest("../../idea/tests/testData/codeInsight/generate/secondaryConstructors/primaryExists.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("properties.kt")
|
||||
public void testProperties() throws Exception {
|
||||
runTest("../../idea/tests/testData/codeInsight/generate/secondaryConstructors/properties.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("propertiesWithKeywords.kt")
|
||||
public void testPropertiesWithKeywords() throws Exception {
|
||||
runTest("../../idea/tests/testData/codeInsight/generate/secondaryConstructors/propertiesWithKeywords.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("propertiesWithSupers.kt")
|
||||
public void testPropertiesWithSupers() throws Exception {
|
||||
runTest("../../idea/tests/testData/codeInsight/generate/secondaryConstructors/propertiesWithSupers.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("superInvisible.kt")
|
||||
public void testSuperInvisible() throws Exception {
|
||||
runTest("../../idea/tests/testData/codeInsight/generate/secondaryConstructors/superInvisible.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("supers.kt")
|
||||
public void testSupers() throws Exception {
|
||||
runTest("../../idea/tests/testData/codeInsight/generate/secondaryConstructors/supers.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("supersAllExist.kt")
|
||||
public void testSupersAllExist() throws Exception {
|
||||
runTest("../../idea/tests/testData/codeInsight/generate/secondaryConstructors/supersAllExist.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("supersSomeExist.kt")
|
||||
public void testSupersSomeExist() throws Exception {
|
||||
runTest("../../idea/tests/testData/codeInsight/generate/secondaryConstructors/supersSomeExist.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("supersWithGenerics.kt")
|
||||
public void testSupersWithGenerics() throws Exception {
|
||||
runTest("../../idea/tests/testData/codeInsight/generate/secondaryConstructors/supersWithGenerics.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("supersWithVarargs.kt")
|
||||
public void testSupersWithVarargs() throws Exception {
|
||||
runTest("../../idea/tests/testData/codeInsight/generate/secondaryConstructors/supersWithVarargs.kt");
|
||||
}
|
||||
}
|
||||
+5
@@ -75,6 +75,11 @@ public class CodeInsightActionTestGenerated extends AbstractCodeInsightActionTes
|
||||
runTest("testData/codeInsight/generate/secondaryConstructors/propertiesWithSupers.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("superInvisible.kt")
|
||||
public void testSuperInvisible() throws Exception {
|
||||
runTest("testData/codeInsight/generate/secondaryConstructors/superInvisible.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("supers.kt")
|
||||
public void testSupers() throws Exception {
|
||||
runTest("testData/codeInsight/generate/secondaryConstructors/supers.kt");
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
// ACTION_CLASS: org.jetbrains.kotlin.idea.actions.generate.KotlinGenerateSecondaryConstructorAction
|
||||
class Foo<U> : Base<U, Int> {
|
||||
val x = 1
|
||||
|
||||
<selection><caret></selection>constructor(x: U) : super(x)
|
||||
constructor(x: U, y: Int) : super(x, y)
|
||||
|
||||
fun foo() {
|
||||
|
||||
}
|
||||
|
||||
fun bar() {
|
||||
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
// ACTION_CLASS: org.jetbrains.kotlin.idea.actions.generate.KotlinGenerateSecondaryConstructorAction
|
||||
open class Base(n: Int) {
|
||||
constructor(a: Int, b: Int): this(a + b)
|
||||
}
|
||||
|
||||
class Foo : Base {
|
||||
val n: Int
|
||||
|
||||
val x = 1
|
||||
|
||||
<selection><caret></selection>constructor(n: Int, n1: Int) : super(n) {
|
||||
this.n = n1
|
||||
}
|
||||
|
||||
constructor(a: Int, b: Int, n: Int) : super(a, b) {
|
||||
this.n = n
|
||||
}
|
||||
|
||||
fun foo() {
|
||||
|
||||
}
|
||||
|
||||
fun bar() {
|
||||
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// ACTION_CLASS: org.jetbrains.kotlin.idea.actions.generate.KotlinGenerateSecondaryConstructorAction
|
||||
open class Base(n: Int) {
|
||||
private constructor(a: Int, b: Int): this(a + b)
|
||||
}
|
||||
|
||||
class Foo : Base {<caret>
|
||||
val x = 1
|
||||
|
||||
fun foo() {
|
||||
|
||||
}
|
||||
|
||||
fun bar() {
|
||||
|
||||
}
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
// ACTION_CLASS: org.jetbrains.kotlin.idea.actions.generate.KotlinGenerateSecondaryConstructorAction
|
||||
open class Base(n: Int) {
|
||||
private constructor(a: Int, b: Int): this(a + b)
|
||||
}
|
||||
|
||||
class Foo : Base {
|
||||
val x = 1
|
||||
|
||||
<selection><caret></selection>constructor(n: Int) : super(n)
|
||||
|
||||
fun foo() {
|
||||
|
||||
}
|
||||
|
||||
fun bar() {
|
||||
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// ACTION_CLASS: org.jetbrains.kotlin.idea.actions.generate.KotlinGenerateSecondaryConstructorAction
|
||||
open class Base(n: Int) {
|
||||
constructor(a: Int, b: Int): this(a + b)
|
||||
}
|
||||
|
||||
class Foo : Base {
|
||||
val x = 1
|
||||
|
||||
<selection><caret></selection>constructor(n: Int) : super(n)
|
||||
constructor(a: Int, b: Int) : super(a, b)
|
||||
|
||||
fun foo() {
|
||||
|
||||
}
|
||||
|
||||
fun bar() {
|
||||
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// ACTION_CLASS: org.jetbrains.kotlin.idea.actions.generate.KotlinGenerateSecondaryConstructorAction
|
||||
open class Base<X, Y>(n: X) {
|
||||
constructor(x: X, y: Y): this(x)
|
||||
}
|
||||
|
||||
class Foo<U> : Base<U, Int> {
|
||||
val x = 1
|
||||
|
||||
<selection><caret></selection>constructor(n: U) : super(n)
|
||||
constructor(x: U, y: Int) : super(x, y)
|
||||
|
||||
fun foo() {
|
||||
|
||||
}
|
||||
|
||||
fun bar() {
|
||||
|
||||
}
|
||||
}
|
||||
+5
@@ -8,6 +8,7 @@ import org.jetbrains.kotlin.idea.k2.AbstractKotlinFirJoinLinesTest
|
||||
import org.jetbrains.kotlin.idea.k2.AbstractKotlinFirPairMatcherTest
|
||||
import org.jetbrains.kotlin.idea.k2.copyPaste.AbstractK2InsertImportOnPasteTest
|
||||
import org.jetbrains.kotlin.idea.k2.generate.AbstractFirGenerateHashCodeAndEqualsActionTest
|
||||
import org.jetbrains.kotlin.idea.k2.generate.AbstractFirGenerateSecondaryConstructorActionTest
|
||||
import org.jetbrains.kotlin.idea.k2.generate.AbstractFirGenerateToStringActionTest
|
||||
import org.jetbrains.kotlin.idea.k2.hierarchy.AbstractFirHierarchyTest
|
||||
import org.jetbrains.kotlin.idea.k2.hierarchy.AbstractFirHierarchyWithLibTest
|
||||
@@ -156,6 +157,10 @@ internal fun MutableTWorkspace.generateK2CodeInsightTests() {
|
||||
model("../../../idea/tests/testData/codeInsight/generate/toString")
|
||||
}
|
||||
|
||||
testClass<AbstractFirGenerateSecondaryConstructorActionTest> {
|
||||
model("../../../idea/tests/testData/codeInsight/generate/secondaryConstructors")
|
||||
}
|
||||
|
||||
testClass<AbstractKotlinFirJoinLinesTest> {
|
||||
model("../../../idea/tests/testData/joinLines")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user