From c7f3a31517b471e918652e4ee0ac1a27990649b0 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Wed, 17 Feb 2016 17:06:59 +0300 Subject: [PATCH] Create subclass intention implemented #KT-8473 Fixed Can be used for implementing interfaces / abstract classes / sealed classes or extending open classes --- .../org/jetbrains/kotlin/psi/KtPsiFactory.kt | 93 +++++++++ .../jetbrains/kotlin/psi/psiUtil/ktPsiUtil.kt | 2 + .../after.kt.template | 9 + .../before.kt.template | 3 + .../description.html | 5 + idea/src/META-INF/plugin.xml | 5 + .../CreateKotlinSubClassIntention.kt | 195 ++++++++++++++++++ idea/testData/quickfix/implement/abstract.kt | 8 + .../quickfix/implement/abstract.kt.after | 19 ++ .../testData/quickfix/implement/annotation.kt | 4 + idea/testData/quickfix/implement/enum.kt | 10 + .../testData/quickfix/implement/finalClass.kt | 3 + .../quickfix/implement/inCompanion.kt | 8 + .../quickfix/implement/inCompanion.kt.after | 10 + .../quickfix/implement/inInternalCompanion.kt | 8 + .../implement/inInternalCompanion.kt.after | 10 + .../quickfix/implement/inPrivateCompanion.kt | 8 + .../implement/inPrivateCompanion.kt.after | 10 + .../implement/inProtectedCompanion.kt | 8 + .../implement/inProtectedCompanion.kt.after | 10 + .../quickfix/implement/incorrectRange.kt | 7 + idea/testData/quickfix/implement/inner.kt | 8 + .../quickfix/implement/inner.kt.after | 14 ++ idea/testData/quickfix/implement/interface.kt | 8 + .../quickfix/implement/interface.kt.after | 14 ++ idea/testData/quickfix/implement/local.kt | 8 + idea/testData/quickfix/implement/nested.kt | 16 ++ .../quickfix/implement/nested.kt.after | 25 +++ .../implement/nestedPrivateInterface.kt | 8 + .../implement/nestedPrivateInterface.kt.after | 15 ++ .../implement/noDefaultConstructor.kt | 3 + idea/testData/quickfix/implement/private.kt | 4 + .../quickfix/implement/private.kt.after | 5 + .../quickfix/implement/privateConstructor.kt | 3 + .../quickfix/implement/privateNested.kt | 10 + .../quickfix/implement/privateNested.kt.after | 12 ++ .../implement/privateNestedWithConflict.kt | 12 ++ .../privateNestedWithConflict.kt.after | 14 ++ idea/testData/quickfix/implement/protected.kt | 6 + .../quickfix/implement/protected.kt.after | 7 + idea/testData/quickfix/implement/sealed.kt | 6 + .../quickfix/implement/sealed.kt.after | 11 + .../quickfix/implement/sealedEmpty.kt | 4 + .../quickfix/implement/sealedEmpty.kt.after | 6 + .../quickfix/implement/sealedWithConflict.kt | 10 + .../implement/sealedWithConflict.kt.after | 16 ++ .../quickfix/implement/typeParameter.kt | 4 + .../quickfix/implement/typeParameter.kt.after | 5 + .../quickfix/implement/typeParameterOut.kt | 4 + .../implement/typeParameterOut.kt.after | 5 + .../quickfix/implement/typeParameterWhere.kt | 4 + .../implement/typeParameterWhere.kt.after | 5 + .../quickfix/implement/typeParametersClass.kt | 4 + .../implement/typeParametersClass.kt.after | 5 + .../idea/quickfix/QuickFixTestGenerated.java | 171 +++++++++++++++ 55 files changed, 887 insertions(+) create mode 100644 idea/resources/intentionDescriptions/CreatekotlinSubClassIntention/after.kt.template create mode 100644 idea/resources/intentionDescriptions/CreatekotlinSubClassIntention/before.kt.template create mode 100644 idea/resources/intentionDescriptions/CreatekotlinSubClassIntention/description.html create mode 100644 idea/src/org/jetbrains/kotlin/idea/intentions/CreateKotlinSubClassIntention.kt create mode 100644 idea/testData/quickfix/implement/abstract.kt create mode 100644 idea/testData/quickfix/implement/abstract.kt.after create mode 100644 idea/testData/quickfix/implement/annotation.kt create mode 100644 idea/testData/quickfix/implement/enum.kt create mode 100644 idea/testData/quickfix/implement/finalClass.kt create mode 100644 idea/testData/quickfix/implement/inCompanion.kt create mode 100644 idea/testData/quickfix/implement/inCompanion.kt.after create mode 100644 idea/testData/quickfix/implement/inInternalCompanion.kt create mode 100644 idea/testData/quickfix/implement/inInternalCompanion.kt.after create mode 100644 idea/testData/quickfix/implement/inPrivateCompanion.kt create mode 100644 idea/testData/quickfix/implement/inPrivateCompanion.kt.after create mode 100644 idea/testData/quickfix/implement/inProtectedCompanion.kt create mode 100644 idea/testData/quickfix/implement/inProtectedCompanion.kt.after create mode 100644 idea/testData/quickfix/implement/incorrectRange.kt create mode 100644 idea/testData/quickfix/implement/inner.kt create mode 100644 idea/testData/quickfix/implement/inner.kt.after create mode 100644 idea/testData/quickfix/implement/interface.kt create mode 100644 idea/testData/quickfix/implement/interface.kt.after create mode 100644 idea/testData/quickfix/implement/local.kt create mode 100644 idea/testData/quickfix/implement/nested.kt create mode 100644 idea/testData/quickfix/implement/nested.kt.after create mode 100644 idea/testData/quickfix/implement/nestedPrivateInterface.kt create mode 100644 idea/testData/quickfix/implement/nestedPrivateInterface.kt.after create mode 100644 idea/testData/quickfix/implement/noDefaultConstructor.kt create mode 100644 idea/testData/quickfix/implement/private.kt create mode 100644 idea/testData/quickfix/implement/private.kt.after create mode 100644 idea/testData/quickfix/implement/privateConstructor.kt create mode 100644 idea/testData/quickfix/implement/privateNested.kt create mode 100644 idea/testData/quickfix/implement/privateNested.kt.after create mode 100644 idea/testData/quickfix/implement/privateNestedWithConflict.kt create mode 100644 idea/testData/quickfix/implement/privateNestedWithConflict.kt.after create mode 100644 idea/testData/quickfix/implement/protected.kt create mode 100644 idea/testData/quickfix/implement/protected.kt.after create mode 100644 idea/testData/quickfix/implement/sealed.kt create mode 100644 idea/testData/quickfix/implement/sealed.kt.after create mode 100644 idea/testData/quickfix/implement/sealedEmpty.kt create mode 100644 idea/testData/quickfix/implement/sealedEmpty.kt.after create mode 100644 idea/testData/quickfix/implement/sealedWithConflict.kt create mode 100644 idea/testData/quickfix/implement/sealedWithConflict.kt.after create mode 100644 idea/testData/quickfix/implement/typeParameter.kt create mode 100644 idea/testData/quickfix/implement/typeParameter.kt.after create mode 100644 idea/testData/quickfix/implement/typeParameterOut.kt create mode 100644 idea/testData/quickfix/implement/typeParameterOut.kt.after create mode 100644 idea/testData/quickfix/implement/typeParameterWhere.kt create mode 100644 idea/testData/quickfix/implement/typeParameterWhere.kt.after create mode 100644 idea/testData/quickfix/implement/typeParametersClass.kt create mode 100644 idea/testData/quickfix/implement/typeParametersClass.kt.after diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiFactory.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiFactory.kt index c2fccc067f7..2e55c141598 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiFactory.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiFactory.kt @@ -427,6 +427,99 @@ class KtPsiFactory(private val project: Project) { return createClass("class A { constructor()$colonOrEmpty$text {}").getSecondaryConstructors().first().getDelegationCall() } + class ClassHeaderBuilder { + + enum class State { + MODIFIERS, + NAME, + TYPE_PARAMETERS, + BASE_CLASS, + TYPE_CONSTRAINTS, + DONE + } + private val sb = StringBuilder() + private var state = State.MODIFIERS + + fun modifier(modifier: String): ClassHeaderBuilder { + assert(state == State.MODIFIERS) + + sb.append(modifier) + + return this + } + + private fun placeKeyword() { + assert(state == State.MODIFIERS) + + if (sb.length != 0) { + sb.append(" ") + } + sb.append("class ") + + state = State.NAME + } + + + fun name(name: String): ClassHeaderBuilder { + placeKeyword() + + sb.append(name) + state = State.TYPE_PARAMETERS + + return this + } + + private fun appendInAngleBrackets(values: Collection) { + if (values.isNotEmpty()) { + sb.append(values.joinToString(", ", "<", ">")) + } + } + + fun typeParameters(values: Collection): ClassHeaderBuilder { + assert(state == State.TYPE_PARAMETERS) + + appendInAngleBrackets(values) + state = State.BASE_CLASS + + return this + } + + fun baseClass(name: String, typeArguments: Collection, isInterface: Boolean): ClassHeaderBuilder { + assert(state == State.BASE_CLASS) + + sb.append(" : $name") + appendInAngleBrackets(typeArguments) + if (!isInterface) { + sb.append("()") + } + + state = State.TYPE_CONSTRAINTS + + return this + } + + fun typeConstraints(values: Collection): ClassHeaderBuilder { + assert(state == State.TYPE_CONSTRAINTS) + + if (!values.isEmpty()) { + sb.append(values.joinToString(", ", " where ", "", -1, "")) + } + state = State.DONE + + return this + } + + fun transform(f: StringBuilder.() -> Unit) = sb.f() + + fun asString(): String { + if (state != State.DONE) { + state = State.DONE + } + + return sb.toString() + } + } + class CallableBuilder(private val target: Target) { enum class Target { FUNCTION, diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/ktPsiUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/ktPsiUtil.kt index 4a0abec0232..7bb5c0de127 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/ktPsiUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/ktPsiUtil.kt @@ -345,6 +345,8 @@ fun PsiElement.parameterIndex(): Int { fun KtModifierListOwner.isPrivate(): Boolean = hasModifier(KtTokens.PRIVATE_KEYWORD) +fun KtModifierListOwner.isProtected(): Boolean = hasModifier(KtTokens.PROTECTED_KEYWORD) + fun KtSimpleNameExpression.isImportDirectiveExpression(): Boolean { val parent = parent return parent is KtImportDirective || parent?.parent is KtImportDirective diff --git a/idea/resources/intentionDescriptions/CreatekotlinSubClassIntention/after.kt.template b/idea/resources/intentionDescriptions/CreatekotlinSubClassIntention/after.kt.template new file mode 100644 index 00000000000..7123c3cadd4 --- /dev/null +++ b/idea/resources/intentionDescriptions/CreatekotlinSubClassIntention/after.kt.template @@ -0,0 +1,9 @@ +interface A { + fun foo(): Int +} + +class B : A { + override fun foo(): Int { + throw UnsupportedOperationException() + } +} \ No newline at end of file diff --git a/idea/resources/intentionDescriptions/CreatekotlinSubClassIntention/before.kt.template b/idea/resources/intentionDescriptions/CreatekotlinSubClassIntention/before.kt.template new file mode 100644 index 00000000000..95856f4b65c --- /dev/null +++ b/idea/resources/intentionDescriptions/CreatekotlinSubClassIntention/before.kt.template @@ -0,0 +1,3 @@ +interface A { + fun foo(): Int< +} \ No newline at end of file diff --git a/idea/resources/intentionDescriptions/CreatekotlinSubClassIntention/description.html b/idea/resources/intentionDescriptions/CreatekotlinSubClassIntention/description.html new file mode 100644 index 00000000000..125b5ea7d15 --- /dev/null +++ b/idea/resources/intentionDescriptions/CreatekotlinSubClassIntention/description.html @@ -0,0 +1,5 @@ + + +This intention creates default implementation for an interface or an abstract class, creates subclass of a sealed or open class + + \ No newline at end of file diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 9d026691112..6e18b3a11d4 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -1175,6 +1175,11 @@ Kotlin + + org.jetbrains.kotlin.idea.intentions.CreateKotlinSubClassIntention + Kotlin + + (KtClass::class.java, "Create Kotlin subclass") { + + override fun applicabilityRange(element: KtClass): TextRange? { + val baseClass = element + if (baseClass.name == null || baseClass.getParentOfType(true) != null) { + // Local / anonymous classes are not supported + return null + } + if (!baseClass.isInterface() && !baseClass.isSealed() && !baseClass.isAbstract() && !baseClass.hasModifier(KtTokens.OPEN_KEYWORD)) { + return null + } + val primaryConstructor = baseClass.getPrimaryConstructor() + if (!baseClass.isInterface() && primaryConstructor != null) { + val constructors = baseClass.getSecondaryConstructors() + primaryConstructor + if (constructors.none() { + !it.isPrivate() && + it.getValueParameters().all { it.hasDefaultValue() } + }) { + // At this moment we require non-private default constructor + // TODO: handle non-private constructors with parameters + return null + } + } + text = getImplementTitle(baseClass) + return TextRange(baseClass.startOffset, baseClass.getBody()?.lBrace?.startOffset ?: baseClass.endOffset) + } + + private fun getImplementTitle(baseClass: KtClass) = + when { + baseClass.isInterface() -> "Implement interface" + baseClass.isAbstract() -> "Implement abstract class" + baseClass.isSealed() -> "Implement sealed class" + else /* open class */ -> "Create subclass" + } + + override fun applyTo(element: KtClass, editor: Editor?) { + if (editor == null) throw IllegalArgumentException("This intention requires an editor") + val name = element.name ?: throw IllegalStateException("This intention should not be applied to anonymous classes") + val baseClass = element + if (baseClass.isSealed()) { + createSealedSubclass(baseClass, name, editor) + } + else { + createExternalSubclass(baseClass, name, editor) + } + } + + private fun defaultTargetName(baseName: String) = "$baseName$IMPL_SUFFIX" + + private fun KtClassOrObject.hasSameDeclaration(name: String) = declarations.any { it is KtNamedDeclaration && it.name == name } + + private fun targetNameWithoutConflicts(baseName: String, container: KtClassOrObject?) = + KotlinNameSuggester.suggestNameByName(defaultTargetName(baseName)) { container?.hasSameDeclaration(it) != true } + + private fun createSealedSubclass(sealedClass: KtClass, sealedName: String, editor: Editor) { + val project = sealedClass.project + val builder = buildClassHeader(targetNameWithoutConflicts(sealedName, sealedClass), sealedClass, sealedName) + val classFromText = KtPsiFactory(project).createClass(builder.asString()) + val body = sealedClass.getOrCreateBody() + val klass = body.addBefore(classFromText, body.rBrace) as KtClass + PsiElementRenameHandler.rename(klass, project, sealedClass, editor) + chooseAndImplementMethods(project, klass, editor) + } + + private fun createExternalSubclass(baseClass: KtClass, baseName: String, editor: Editor) { + var container: KtClassOrObject = baseClass + var name = baseName + var visibility = ModifiersChecker.resolveVisibilityFromModifiers(baseClass, Visibilities.PUBLIC) + while (!container.isPrivate() && !container.isProtected() && !(container is KtClass && container.isInner())) { + val parent = container.containingClassOrObject + if (parent != null) { + val parentName = parent.name + if (parentName != null) { + container = parent + name = "$parentName.$name" + val parentVisibility = ModifiersChecker.resolveVisibilityFromModifiers(parent, visibility) + if (Visibilities.compare(parentVisibility, visibility) ?: 0 < 0) { + visibility = parentVisibility + } + } + } + if (container != parent) { + break + } + } + val project = baseClass.project + val factory = KtPsiFactory(project) + if (container.containingClassOrObject == null && !ApplicationManager.getApplication().isUnitTestMode) { + val dlg = chooseSubclassToCreate(baseClass, baseName) ?: return + val targetName = dlg.className + val file = getOrCreateKotlinFile("$targetName.kt", dlg.targetDirectory)!! + val builder = buildClassHeader(targetName, baseClass, "${baseClass.fqName!!.asString()}") + file.add(factory.createClass(builder.asString())) + val klass = file.getChildOfType()!! + ShortenReferences.DEFAULT.process(klass) + chooseAndImplementMethods(project, klass, CodeInsightUtil.positionCursor(project, file, klass) ?: editor) + } + else { + val builder = buildClassHeader(targetNameWithoutConflicts(baseName, baseClass.containingClassOrObject), + baseClass, name, visibility) + val classFromText = factory.createClass(builder.asString()) + val klass = container.parent.addAfter(classFromText, container) as KtClass + PsiElementRenameHandler.rename(klass, project, container, editor) + chooseAndImplementMethods(project, klass, editor) + } + } + + private fun chooseSubclassToCreate(baseClass: KtClass, baseName: String): CreateClassDialog? { + val sourceDir = baseClass.containingFile.containingDirectory + + val aPackage = JavaDirectoryService.getInstance().getPackage(sourceDir) + val dialog = object : CreateClassDialog( + baseClass.project, text, + targetNameWithoutConflicts(baseName, baseClass.containingClassOrObject), + aPackage?.qualifiedName ?: "", + CreateClassKind.CLASS, true, + ModuleUtilCore.findModuleForPsiElement(baseClass) + ) { + override fun getBaseDir(packageName: String) = sourceDir + + override fun reportBaseInTestSelectionInSource() = true + } + return if (!dialog.showAndGet() || dialog.targetDirectory == null) null else dialog + } + + private fun buildClassHeader( + targetName: String, + baseClass: KtClass, + baseName: String, + defaultVisibility: Visibility = ModifiersChecker.resolveVisibilityFromModifiers(baseClass, Visibilities.PUBLIC) + ): ClassHeaderBuilder { + return ClassHeaderBuilder().apply { + if (!baseClass.isInterface()) { + if (defaultVisibility != Visibilities.PUBLIC) { + modifier(defaultVisibility.name) + } + if (baseClass.isInner()) { + modifier(KtTokens.INNER_KEYWORD.value) + } + } + name(targetName) + val typeParameters = baseClass.typeParameterList?.parameters + typeParameters(typeParameters?.map { it.text }.orEmpty()) + baseClass(baseName, typeParameters?.map { it.name ?: "" }.orEmpty(), baseClass.isInterface()) + typeConstraints(baseClass.typeConstraintList?.constraints?.map { it.text }.orEmpty()) + } + } + + private fun chooseAndImplementMethods(project: Project, targetClass: KtClass, editor: Editor) { + editor.caretModel.moveToOffset(targetClass.textRange.startOffset) + ImplementMembersHandler().invoke(project, editor, targetClass.containingFile) + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/implement/abstract.kt b/idea/testData/quickfix/implement/abstract.kt new file mode 100644 index 00000000000..da7ffb185dd --- /dev/null +++ b/idea/testData/quickfix/implement/abstract.kt @@ -0,0 +1,8 @@ +// "Implement abstract class" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +private abstract class Base { + abstract var x: Int + + abstract fun toInt(arg: String): Int +} \ No newline at end of file diff --git a/idea/testData/quickfix/implement/abstract.kt.after b/idea/testData/quickfix/implement/abstract.kt.after new file mode 100644 index 00000000000..a8c30fbbf41 --- /dev/null +++ b/idea/testData/quickfix/implement/abstract.kt.after @@ -0,0 +1,19 @@ +// "Implement abstract class" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +private abstract class Base { + abstract var x: Int + + abstract fun toInt(arg: String): Int +} + +private class BaseImpl : Base() { + override var x: Int + get() = throw UnsupportedOperationException() + set(value) { + } + + override fun toInt(arg: String): Int { + throw UnsupportedOperationException() + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/implement/annotation.kt b/idea/testData/quickfix/implement/annotation.kt new file mode 100644 index 00000000000..46f1cfbcfc0 --- /dev/null +++ b/idea/testData/quickfix/implement/annotation.kt @@ -0,0 +1,4 @@ +// "Create subclass" "false" + +annotation class My(val x: Int) + diff --git a/idea/testData/quickfix/implement/enum.kt b/idea/testData/quickfix/implement/enum.kt new file mode 100644 index 00000000000..e88a58f4fed --- /dev/null +++ b/idea/testData/quickfix/implement/enum.kt @@ -0,0 +1,10 @@ +// "Create subclass" "false" +// ACTION: Create test + +enum class My { + SINGLE { + override fun foo(): Int = 0 + }; + + abstract fun foo(): Int +} diff --git a/idea/testData/quickfix/implement/finalClass.kt b/idea/testData/quickfix/implement/finalClass.kt new file mode 100644 index 00000000000..4c5e65f11b5 --- /dev/null +++ b/idea/testData/quickfix/implement/finalClass.kt @@ -0,0 +1,3 @@ +// "Create subclass" "false" + +class Base \ No newline at end of file diff --git a/idea/testData/quickfix/implement/inCompanion.kt b/idea/testData/quickfix/implement/inCompanion.kt new file mode 100644 index 00000000000..52425c87c4b --- /dev/null +++ b/idea/testData/quickfix/implement/inCompanion.kt @@ -0,0 +1,8 @@ +// "Create subclass" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +class Container { + companion object { + open class Base + } +} diff --git a/idea/testData/quickfix/implement/inCompanion.kt.after b/idea/testData/quickfix/implement/inCompanion.kt.after new file mode 100644 index 00000000000..504a3de6cca --- /dev/null +++ b/idea/testData/quickfix/implement/inCompanion.kt.after @@ -0,0 +1,10 @@ +// "Create subclass" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +class Container { + companion object { + open class Base + } +} + +class BaseImpl : Container.Companion.Base() diff --git a/idea/testData/quickfix/implement/inInternalCompanion.kt b/idea/testData/quickfix/implement/inInternalCompanion.kt new file mode 100644 index 00000000000..5b614fe4029 --- /dev/null +++ b/idea/testData/quickfix/implement/inInternalCompanion.kt @@ -0,0 +1,8 @@ +// "Create subclass" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +class Container { + internal companion object { + open class Base + } +} diff --git a/idea/testData/quickfix/implement/inInternalCompanion.kt.after b/idea/testData/quickfix/implement/inInternalCompanion.kt.after new file mode 100644 index 00000000000..b5126f5df0c --- /dev/null +++ b/idea/testData/quickfix/implement/inInternalCompanion.kt.after @@ -0,0 +1,10 @@ +// "Create subclass" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +class Container { + internal companion object { + open class Base + } +} + +internal class BaseImpl : Container.Companion.Base() diff --git a/idea/testData/quickfix/implement/inPrivateCompanion.kt b/idea/testData/quickfix/implement/inPrivateCompanion.kt new file mode 100644 index 00000000000..02c01f5ed05 --- /dev/null +++ b/idea/testData/quickfix/implement/inPrivateCompanion.kt @@ -0,0 +1,8 @@ +// "Create subclass" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +class Container { + private companion object { + open class Base + } +} diff --git a/idea/testData/quickfix/implement/inPrivateCompanion.kt.after b/idea/testData/quickfix/implement/inPrivateCompanion.kt.after new file mode 100644 index 00000000000..033b56acf4c --- /dev/null +++ b/idea/testData/quickfix/implement/inPrivateCompanion.kt.after @@ -0,0 +1,10 @@ +// "Create subclass" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +class Container { + private companion object { + open class Base + } + + private class BaseImpl : Companion.Base() +} diff --git a/idea/testData/quickfix/implement/inProtectedCompanion.kt b/idea/testData/quickfix/implement/inProtectedCompanion.kt new file mode 100644 index 00000000000..6a261a34b9b --- /dev/null +++ b/idea/testData/quickfix/implement/inProtectedCompanion.kt @@ -0,0 +1,8 @@ +// "Create subclass" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +class Container { + protected companion object { + open class Base + } +} diff --git a/idea/testData/quickfix/implement/inProtectedCompanion.kt.after b/idea/testData/quickfix/implement/inProtectedCompanion.kt.after new file mode 100644 index 00000000000..db4ecaab943 --- /dev/null +++ b/idea/testData/quickfix/implement/inProtectedCompanion.kt.after @@ -0,0 +1,10 @@ +// "Create subclass" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +class Container { + protected companion object { + open class Base + } + + protected class BaseImpl : Companion.Base() +} diff --git a/idea/testData/quickfix/implement/incorrectRange.kt b/idea/testData/quickfix/implement/incorrectRange.kt new file mode 100644 index 00000000000..d8030dbda0a --- /dev/null +++ b/idea/testData/quickfix/implement/incorrectRange.kt @@ -0,0 +1,7 @@ +// "Implement interface" "false" +// ACTION: Convert function to property +// ACTION: Convert member to extension + +interface Base { + fun foo(): Int +} \ No newline at end of file diff --git a/idea/testData/quickfix/implement/inner.kt b/idea/testData/quickfix/implement/inner.kt new file mode 100644 index 00000000000..0afb5349d32 --- /dev/null +++ b/idea/testData/quickfix/implement/inner.kt @@ -0,0 +1,8 @@ +// "Implement abstract class" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +class Container { + inner abstract class Base { + abstract fun foo(): String + } +} diff --git a/idea/testData/quickfix/implement/inner.kt.after b/idea/testData/quickfix/implement/inner.kt.after new file mode 100644 index 00000000000..35411d48bed --- /dev/null +++ b/idea/testData/quickfix/implement/inner.kt.after @@ -0,0 +1,14 @@ +// "Implement abstract class" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +class Container { + inner abstract class Base { + abstract fun foo(): String + } + + inner class BaseImpl : Base() { + override fun foo(): String { + throw UnsupportedOperationException() + } + } +} diff --git a/idea/testData/quickfix/implement/interface.kt b/idea/testData/quickfix/implement/interface.kt new file mode 100644 index 00000000000..3937ebf6d99 --- /dev/null +++ b/idea/testData/quickfix/implement/interface.kt @@ -0,0 +1,8 @@ +// "Implement interface" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +interface Base { + fun foo(x: Int): Int + + fun bar(y: String) = y +} diff --git a/idea/testData/quickfix/implement/interface.kt.after b/idea/testData/quickfix/implement/interface.kt.after new file mode 100644 index 00000000000..692dc5d8bd8 --- /dev/null +++ b/idea/testData/quickfix/implement/interface.kt.after @@ -0,0 +1,14 @@ +// "Implement interface" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +interface Base { + fun foo(x: Int): Int + + fun bar(y: String) = y +} + +class BaseImpl : Base { + override fun foo(x: Int): Int { + throw UnsupportedOperationException() + } +} diff --git a/idea/testData/quickfix/implement/local.kt b/idea/testData/quickfix/implement/local.kt new file mode 100644 index 00000000000..a8647eb53e5 --- /dev/null +++ b/idea/testData/quickfix/implement/local.kt @@ -0,0 +1,8 @@ +// "Implement abstract class" "false" + +fun foo() { + abstract class My { + abstract fun bar(): Int + } +} + diff --git a/idea/testData/quickfix/implement/nested.kt b/idea/testData/quickfix/implement/nested.kt new file mode 100644 index 00000000000..ebd7be1ba0b --- /dev/null +++ b/idea/testData/quickfix/implement/nested.kt @@ -0,0 +1,16 @@ +// "Implement interface" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +class Container { + interface Base { + val x: Boolean + + val y: Double + get() = 3.14 + + fun foo(): String = "" + + fun bar(z: Int): String + } +} + diff --git a/idea/testData/quickfix/implement/nested.kt.after b/idea/testData/quickfix/implement/nested.kt.after new file mode 100644 index 00000000000..f3cd6daf292 --- /dev/null +++ b/idea/testData/quickfix/implement/nested.kt.after @@ -0,0 +1,25 @@ +// "Implement interface" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +class Container { + interface Base { + val x: Boolean + + val y: Double + get() = 3.14 + + fun foo(): String = "" + + fun bar(z: Int): String + } +} + +class BaseImpl : Container.Base { + override val x: Boolean + get() = throw UnsupportedOperationException() + + override fun bar(z: Int): String { + throw UnsupportedOperationException() + } +} + diff --git a/idea/testData/quickfix/implement/nestedPrivateInterface.kt b/idea/testData/quickfix/implement/nestedPrivateInterface.kt new file mode 100644 index 00000000000..c8031e4c7f9 --- /dev/null +++ b/idea/testData/quickfix/implement/nestedPrivateInterface.kt @@ -0,0 +1,8 @@ +// "Implement interface" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +class Container { + private interface Base { + var z: Double + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/implement/nestedPrivateInterface.kt.after b/idea/testData/quickfix/implement/nestedPrivateInterface.kt.after new file mode 100644 index 00000000000..d625c3980a9 --- /dev/null +++ b/idea/testData/quickfix/implement/nestedPrivateInterface.kt.after @@ -0,0 +1,15 @@ +// "Implement interface" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +class Container { + private interface Base { + var z: Double + } + + class BaseImpl : Base { + override var z: Double + get() = throw UnsupportedOperationException() + set(value) { + } + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/implement/noDefaultConstructor.kt b/idea/testData/quickfix/implement/noDefaultConstructor.kt new file mode 100644 index 00000000000..f7adbb4ad65 --- /dev/null +++ b/idea/testData/quickfix/implement/noDefaultConstructor.kt @@ -0,0 +1,3 @@ +// "Implement abstract class" "false" + +abstract class Base(val x: Int) \ No newline at end of file diff --git a/idea/testData/quickfix/implement/private.kt b/idea/testData/quickfix/implement/private.kt new file mode 100644 index 00000000000..321f9c8c74a --- /dev/null +++ b/idea/testData/quickfix/implement/private.kt @@ -0,0 +1,4 @@ +// "Create subclass" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +private open class Base \ No newline at end of file diff --git a/idea/testData/quickfix/implement/private.kt.after b/idea/testData/quickfix/implement/private.kt.after new file mode 100644 index 00000000000..49247c4434a --- /dev/null +++ b/idea/testData/quickfix/implement/private.kt.after @@ -0,0 +1,5 @@ +// "Create subclass" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +private open class Base +private class BaseImpl : Base() \ No newline at end of file diff --git a/idea/testData/quickfix/implement/privateConstructor.kt b/idea/testData/quickfix/implement/privateConstructor.kt new file mode 100644 index 00000000000..805076820bd --- /dev/null +++ b/idea/testData/quickfix/implement/privateConstructor.kt @@ -0,0 +1,3 @@ +// "Implement abstract class" "false" + +abstract class Base private constructor \ No newline at end of file diff --git a/idea/testData/quickfix/implement/privateNested.kt b/idea/testData/quickfix/implement/privateNested.kt new file mode 100644 index 00000000000..0e81b813fbd --- /dev/null +++ b/idea/testData/quickfix/implement/privateNested.kt @@ -0,0 +1,10 @@ +// "Create subclass" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +class Container { + private open class Base { + open var x: String = "" + + open fun foo(): String = "" + } +} diff --git a/idea/testData/quickfix/implement/privateNested.kt.after b/idea/testData/quickfix/implement/privateNested.kt.after new file mode 100644 index 00000000000..a225ecda702 --- /dev/null +++ b/idea/testData/quickfix/implement/privateNested.kt.after @@ -0,0 +1,12 @@ +// "Create subclass" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +class Container { + private open class Base { + open var x: String = "" + + open fun foo(): String = "" + } + + private class BaseImpl : Base() +} diff --git a/idea/testData/quickfix/implement/privateNestedWithConflict.kt b/idea/testData/quickfix/implement/privateNestedWithConflict.kt new file mode 100644 index 00000000000..b52a9acca7a --- /dev/null +++ b/idea/testData/quickfix/implement/privateNestedWithConflict.kt @@ -0,0 +1,12 @@ +// "Create subclass" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +class Container { + private open class Base { + open var x: String = "" + + open fun foo(): String = "" + } + + private class BaseImpl : Base() +} diff --git a/idea/testData/quickfix/implement/privateNestedWithConflict.kt.after b/idea/testData/quickfix/implement/privateNestedWithConflict.kt.after new file mode 100644 index 00000000000..6a28b3dd894 --- /dev/null +++ b/idea/testData/quickfix/implement/privateNestedWithConflict.kt.after @@ -0,0 +1,14 @@ +// "Create subclass" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +class Container { + private open class Base { + open var x: String = "" + + open fun foo(): String = "" + } + + private class BaseImpl1 : Base() + + private class BaseImpl : Base() +} diff --git a/idea/testData/quickfix/implement/protected.kt b/idea/testData/quickfix/implement/protected.kt new file mode 100644 index 00000000000..cd57daca13e --- /dev/null +++ b/idea/testData/quickfix/implement/protected.kt @@ -0,0 +1,6 @@ +// "Implement abstract class" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +class Container { + protected abstract class Base +} \ No newline at end of file diff --git a/idea/testData/quickfix/implement/protected.kt.after b/idea/testData/quickfix/implement/protected.kt.after new file mode 100644 index 00000000000..7a66286b76f --- /dev/null +++ b/idea/testData/quickfix/implement/protected.kt.after @@ -0,0 +1,7 @@ +// "Implement abstract class" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +class Container { + protected abstract class Base + protected class BaseImpl : Base() +} \ No newline at end of file diff --git a/idea/testData/quickfix/implement/sealed.kt b/idea/testData/quickfix/implement/sealed.kt new file mode 100644 index 00000000000..93398b39f75 --- /dev/null +++ b/idea/testData/quickfix/implement/sealed.kt @@ -0,0 +1,6 @@ +// "Implement sealed class" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +sealed class Base { + abstract fun foo(): Int +} \ No newline at end of file diff --git a/idea/testData/quickfix/implement/sealed.kt.after b/idea/testData/quickfix/implement/sealed.kt.after new file mode 100644 index 00000000000..371ef5e66bf --- /dev/null +++ b/idea/testData/quickfix/implement/sealed.kt.after @@ -0,0 +1,11 @@ +// "Implement sealed class" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +sealed class Base { + abstract fun foo(): Int + class BaseImpl : Base() { + override fun foo(): Int { + throw UnsupportedOperationException() + } + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/implement/sealedEmpty.kt b/idea/testData/quickfix/implement/sealedEmpty.kt new file mode 100644 index 00000000000..b10b62726d4 --- /dev/null +++ b/idea/testData/quickfix/implement/sealedEmpty.kt @@ -0,0 +1,4 @@ +// "Implement sealed class" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +sealed class Sealed \ No newline at end of file diff --git a/idea/testData/quickfix/implement/sealedEmpty.kt.after b/idea/testData/quickfix/implement/sealedEmpty.kt.after new file mode 100644 index 00000000000..4b1bee41ba0 --- /dev/null +++ b/idea/testData/quickfix/implement/sealedEmpty.kt.after @@ -0,0 +1,6 @@ +// "Implement sealed class" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +sealed class Sealed { + class SealedImpl : Sealed() +} \ No newline at end of file diff --git a/idea/testData/quickfix/implement/sealedWithConflict.kt b/idea/testData/quickfix/implement/sealedWithConflict.kt new file mode 100644 index 00000000000..ce94ccee4f2 --- /dev/null +++ b/idea/testData/quickfix/implement/sealedWithConflict.kt @@ -0,0 +1,10 @@ +// "Implement sealed class" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +sealed class Base { + abstract fun foo(): Int + + class BaseImpl : Base() { + override fun foo() = throw UnsupportedOperationException() + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/implement/sealedWithConflict.kt.after b/idea/testData/quickfix/implement/sealedWithConflict.kt.after new file mode 100644 index 00000000000..b069f6d9164 --- /dev/null +++ b/idea/testData/quickfix/implement/sealedWithConflict.kt.after @@ -0,0 +1,16 @@ +// "Implement sealed class" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +sealed class Base { + abstract fun foo(): Int + + class BaseImpl : Base() { + override fun foo() = throw UnsupportedOperationException() + } + + class BaseImpl1 : Base() { + override fun foo(): Int { + throw UnsupportedOperationException() + } + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/implement/typeParameter.kt b/idea/testData/quickfix/implement/typeParameter.kt new file mode 100644 index 00000000000..be28d93f12e --- /dev/null +++ b/idea/testData/quickfix/implement/typeParameter.kt @@ -0,0 +1,4 @@ +// "Implement interface" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +interface Base \ No newline at end of file diff --git a/idea/testData/quickfix/implement/typeParameter.kt.after b/idea/testData/quickfix/implement/typeParameter.kt.after new file mode 100644 index 00000000000..22491f0d61e --- /dev/null +++ b/idea/testData/quickfix/implement/typeParameter.kt.after @@ -0,0 +1,5 @@ +// "Implement interface" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +interface Base +class BaseImpl : Base \ No newline at end of file diff --git a/idea/testData/quickfix/implement/typeParameterOut.kt b/idea/testData/quickfix/implement/typeParameterOut.kt new file mode 100644 index 00000000000..7813a8d52e2 --- /dev/null +++ b/idea/testData/quickfix/implement/typeParameterOut.kt @@ -0,0 +1,4 @@ +// "Implement interface" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +interface Base \ No newline at end of file diff --git a/idea/testData/quickfix/implement/typeParameterOut.kt.after b/idea/testData/quickfix/implement/typeParameterOut.kt.after new file mode 100644 index 00000000000..23d45a626c4 --- /dev/null +++ b/idea/testData/quickfix/implement/typeParameterOut.kt.after @@ -0,0 +1,5 @@ +// "Implement interface" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +interface Base +class BaseImpl : Base \ No newline at end of file diff --git a/idea/testData/quickfix/implement/typeParameterWhere.kt b/idea/testData/quickfix/implement/typeParameterWhere.kt new file mode 100644 index 00000000000..ea9911af337 --- /dev/null +++ b/idea/testData/quickfix/implement/typeParameterWhere.kt @@ -0,0 +1,4 @@ +// "Implement interface" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +interface Base where T : Any \ No newline at end of file diff --git a/idea/testData/quickfix/implement/typeParameterWhere.kt.after b/idea/testData/quickfix/implement/typeParameterWhere.kt.after new file mode 100644 index 00000000000..52ce7602494 --- /dev/null +++ b/idea/testData/quickfix/implement/typeParameterWhere.kt.after @@ -0,0 +1,5 @@ +// "Implement interface" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +interface Base where T : Any +class BaseImpl : Base where T : Any \ No newline at end of file diff --git a/idea/testData/quickfix/implement/typeParametersClass.kt b/idea/testData/quickfix/implement/typeParametersClass.kt new file mode 100644 index 00000000000..b22800e8399 --- /dev/null +++ b/idea/testData/quickfix/implement/typeParametersClass.kt @@ -0,0 +1,4 @@ +// "Create subclass" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +open class Base> \ No newline at end of file diff --git a/idea/testData/quickfix/implement/typeParametersClass.kt.after b/idea/testData/quickfix/implement/typeParametersClass.kt.after new file mode 100644 index 00000000000..0fdde9f2e71 --- /dev/null +++ b/idea/testData/quickfix/implement/typeParametersClass.kt.after @@ -0,0 +1,5 @@ +// "Create subclass" "true" +// SHOULD_BE_AVAILABLE_AFTER_EXECUTION + +open class Base> +class BaseImpl> : Base() \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index 5e2d73b549c..eaa76986b91 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -4471,6 +4471,177 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { } } + @TestMetadata("idea/testData/quickfix/implement") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Implement extends AbstractQuickFixTest { + @TestMetadata("abstract.kt") + public void testAbstract() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/implement/abstract.kt"); + doTest(fileName); + } + + public void testAllFilesPresentInImplement() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/implement"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true); + } + + @TestMetadata("annotation.kt") + public void testAnnotation() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/implement/annotation.kt"); + doTest(fileName); + } + + @TestMetadata("enum.kt") + public void testEnum() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/implement/enum.kt"); + doTest(fileName); + } + + @TestMetadata("finalClass.kt") + public void testFinalClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/implement/finalClass.kt"); + doTest(fileName); + } + + @TestMetadata("inCompanion.kt") + public void testInCompanion() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/implement/inCompanion.kt"); + doTest(fileName); + } + + @TestMetadata("inInternalCompanion.kt") + public void testInInternalCompanion() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/implement/inInternalCompanion.kt"); + doTest(fileName); + } + + @TestMetadata("inPrivateCompanion.kt") + public void testInPrivateCompanion() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/implement/inPrivateCompanion.kt"); + doTest(fileName); + } + + @TestMetadata("inProtectedCompanion.kt") + public void testInProtectedCompanion() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/implement/inProtectedCompanion.kt"); + doTest(fileName); + } + + @TestMetadata("incorrectRange.kt") + public void testIncorrectRange() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/implement/incorrectRange.kt"); + doTest(fileName); + } + + @TestMetadata("inner.kt") + public void testInner() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/implement/inner.kt"); + doTest(fileName); + } + + @TestMetadata("interface.kt") + public void testInterface() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/implement/interface.kt"); + doTest(fileName); + } + + @TestMetadata("local.kt") + public void testLocal() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/implement/local.kt"); + doTest(fileName); + } + + @TestMetadata("nested.kt") + public void testNested() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/implement/nested.kt"); + doTest(fileName); + } + + @TestMetadata("nestedPrivateInterface.kt") + public void testNestedPrivateInterface() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/implement/nestedPrivateInterface.kt"); + doTest(fileName); + } + + @TestMetadata("noDefaultConstructor.kt") + public void testNoDefaultConstructor() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/implement/noDefaultConstructor.kt"); + doTest(fileName); + } + + @TestMetadata("private.kt") + public void testPrivate() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/implement/private.kt"); + doTest(fileName); + } + + @TestMetadata("privateConstructor.kt") + public void testPrivateConstructor() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/implement/privateConstructor.kt"); + doTest(fileName); + } + + @TestMetadata("privateNested.kt") + public void testPrivateNested() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/implement/privateNested.kt"); + doTest(fileName); + } + + @TestMetadata("privateNestedWithConflict.kt") + public void testPrivateNestedWithConflict() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/implement/privateNestedWithConflict.kt"); + doTest(fileName); + } + + @TestMetadata("protected.kt") + public void testProtected() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/implement/protected.kt"); + doTest(fileName); + } + + @TestMetadata("sealed.kt") + public void testSealed() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/implement/sealed.kt"); + doTest(fileName); + } + + @TestMetadata("sealedEmpty.kt") + public void testSealedEmpty() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/implement/sealedEmpty.kt"); + doTest(fileName); + } + + @TestMetadata("sealedWithConflict.kt") + public void testSealedWithConflict() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/implement/sealedWithConflict.kt"); + doTest(fileName); + } + + @TestMetadata("typeParameter.kt") + public void testTypeParameter() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/implement/typeParameter.kt"); + doTest(fileName); + } + + @TestMetadata("typeParameterOut.kt") + public void testTypeParameterOut() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/implement/typeParameterOut.kt"); + doTest(fileName); + } + + @TestMetadata("typeParameterWhere.kt") + public void testTypeParameterWhere() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/implement/typeParameterWhere.kt"); + doTest(fileName); + } + + @TestMetadata("typeParametersClass.kt") + public void testTypeParametersClass() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/implement/typeParametersClass.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/testData/quickfix/initializeWithConstructorParameter") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)