Create subclass intention implemented #KT-8473 Fixed
Can be used for implementing interfaces / abstract classes / sealed classes or extending open classes
This commit is contained in:
@@ -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<String>) {
|
||||
if (values.isNotEmpty()) {
|
||||
sb.append(values.joinToString(", ", "<", ">"))
|
||||
}
|
||||
}
|
||||
|
||||
fun typeParameters(values: Collection<String>): ClassHeaderBuilder {
|
||||
assert(state == State.TYPE_PARAMETERS)
|
||||
|
||||
appendInAngleBrackets(values)
|
||||
state = State.BASE_CLASS
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
fun baseClass(name: String, typeArguments: Collection<String>, 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<String>): 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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
interface A {
|
||||
fun foo(): Int
|
||||
}
|
||||
|
||||
<spot>class B : A {
|
||||
override fun foo(): Int {
|
||||
throw UnsupportedOperationException()
|
||||
}
|
||||
}</spot>
|
||||
@@ -0,0 +1,3 @@
|
||||
<spot>interface A</spot> {
|
||||
fun foo(): Int<
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
This intention creates default implementation for an interface or an abstract class, creates subclass of a sealed or open class
|
||||
</body>
|
||||
</html>
|
||||
@@ -1175,6 +1175,11 @@
|
||||
<category>Kotlin</category>
|
||||
</intentionAction>
|
||||
|
||||
<intentionAction>
|
||||
<className>org.jetbrains.kotlin.idea.intentions.CreateKotlinSubClassIntention</className>
|
||||
<category>Kotlin</category>
|
||||
</intentionAction>
|
||||
|
||||
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.ObjectLiteralToLambdaInspection"
|
||||
displayName="Object literal can be converted to lambda"
|
||||
groupName="Kotlin"
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.intentions
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightUtil
|
||||
import com.intellij.codeInsight.daemon.impl.quickfix.CreateClassKind
|
||||
import com.intellij.codeInsight.intention.impl.CreateClassDialog
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.module.ModuleUtilCore
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.refactoring.rename.PsiElementRenameHandler
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
|
||||
import org.jetbrains.kotlin.idea.core.overrideImplement.ImplementMembersHandler
|
||||
import org.jetbrains.kotlin.idea.refactoring.getOrCreateKotlinFile
|
||||
import org.jetbrains.kotlin.idea.util.ShortenReferences
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory.ClassHeaderBuilder
|
||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
import org.jetbrains.kotlin.resolve.ModifiersChecker
|
||||
|
||||
private const val IMPL_SUFFIX = "Impl"
|
||||
|
||||
class CreateKotlinSubClassIntention : SelfTargetingRangeIntention<KtClass>(KtClass::class.java, "Create Kotlin subclass") {
|
||||
|
||||
override fun applicabilityRange(element: KtClass): TextRange? {
|
||||
val baseClass = element
|
||||
if (baseClass.name == null || baseClass.getParentOfType<KtFunction>(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<KtClass>()!!
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// "Implement abstract class" "true"
|
||||
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION
|
||||
|
||||
private abstract class <caret>Base {
|
||||
abstract var x: Int
|
||||
|
||||
abstract fun toInt(arg: String): Int
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// "Create subclass" "false"
|
||||
|
||||
annotation class <caret>My(val x: Int)
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Create subclass" "false"
|
||||
// ACTION: Create test
|
||||
|
||||
enum class <caret>My {
|
||||
SINGLE {
|
||||
override fun foo(): Int = 0
|
||||
};
|
||||
|
||||
abstract fun foo(): Int
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
// "Create subclass" "false"
|
||||
|
||||
class Base
|
||||
@@ -0,0 +1,8 @@
|
||||
// "Create subclass" "true"
|
||||
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION
|
||||
|
||||
class Container {
|
||||
companion object {
|
||||
open class <caret>Base
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Create subclass" "true"
|
||||
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION
|
||||
|
||||
class Container {
|
||||
companion object {
|
||||
open class Base
|
||||
}
|
||||
}
|
||||
|
||||
class BaseImpl : Container.Companion.Base()
|
||||
@@ -0,0 +1,8 @@
|
||||
// "Create subclass" "true"
|
||||
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION
|
||||
|
||||
class Container {
|
||||
internal companion object {
|
||||
open class <caret>Base
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
@@ -0,0 +1,8 @@
|
||||
// "Create subclass" "true"
|
||||
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION
|
||||
|
||||
class Container {
|
||||
private companion object {
|
||||
open class <caret>Base
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// "Create subclass" "true"
|
||||
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION
|
||||
|
||||
class Container {
|
||||
protected companion object {
|
||||
open class <caret>Base
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// "Implement interface" "false"
|
||||
// ACTION: Convert function to property
|
||||
// ACTION: Convert member to extension
|
||||
|
||||
interface Base {
|
||||
fun <caret>foo(): Int
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// "Implement abstract class" "true"
|
||||
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION
|
||||
|
||||
class Container {
|
||||
inner abstract class <caret>Base {
|
||||
abstract fun foo(): String
|
||||
}
|
||||
}
|
||||
+14
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// "Implement interface" "true"
|
||||
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION
|
||||
|
||||
interface <caret>Base {
|
||||
fun foo(x: Int): Int
|
||||
|
||||
fun bar(y: String) = y
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// "Implement abstract class" "false"
|
||||
|
||||
fun foo() {
|
||||
abstract class <caret>My {
|
||||
abstract fun bar(): Int
|
||||
}
|
||||
}
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// "Implement interface" "true"
|
||||
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION
|
||||
|
||||
class Container {
|
||||
interface <caret>Base {
|
||||
val x: Boolean
|
||||
|
||||
val y: Double
|
||||
get() = 3.14
|
||||
|
||||
fun foo(): String = ""
|
||||
|
||||
fun bar(z: Int): String
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
// "Implement interface" "true"
|
||||
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION
|
||||
|
||||
class Container {
|
||||
private interface <caret>Base {
|
||||
var z: Double
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
// "Implement abstract class" "false"
|
||||
|
||||
abstract class Base(val x: Int)
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
// "Create subclass" "true"
|
||||
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION
|
||||
|
||||
private open class <caret>Base
|
||||
@@ -0,0 +1,5 @@
|
||||
// "Create subclass" "true"
|
||||
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION
|
||||
|
||||
private open class Base
|
||||
private class BaseImpl : Base()
|
||||
@@ -0,0 +1,3 @@
|
||||
// "Implement abstract class" "false"
|
||||
|
||||
abstract class Base private constructor
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Create subclass" "true"
|
||||
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION
|
||||
|
||||
class Container {
|
||||
private open class <caret>Base {
|
||||
open var x: String = ""
|
||||
|
||||
open fun foo(): String = ""
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// "Create subclass" "true"
|
||||
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION
|
||||
|
||||
class Container {
|
||||
private open class <caret>Base {
|
||||
open var x: String = ""
|
||||
|
||||
open fun foo(): String = ""
|
||||
}
|
||||
|
||||
private class BaseImpl : Base()
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
// "Implement abstract class" "true"
|
||||
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION
|
||||
|
||||
class Container {
|
||||
protected abstract class <caret>Base
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// "Implement abstract class" "true"
|
||||
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION
|
||||
|
||||
class Container {
|
||||
protected abstract class Base
|
||||
protected class BaseImpl : Base()
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// "Implement sealed class" "true"
|
||||
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION
|
||||
|
||||
sealed class <caret>Base {
|
||||
abstract fun foo(): Int
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// "Implement sealed class" "true"
|
||||
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION
|
||||
|
||||
sealed class <caret>Sealed
|
||||
@@ -0,0 +1,6 @@
|
||||
// "Implement sealed class" "true"
|
||||
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION
|
||||
|
||||
sealed class Sealed {
|
||||
class SealedImpl : Sealed()
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Implement sealed class" "true"
|
||||
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION
|
||||
|
||||
sealed class <caret>Base {
|
||||
abstract fun foo(): Int
|
||||
|
||||
class BaseImpl : Base() {
|
||||
override fun foo() = throw UnsupportedOperationException()
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// "Implement interface" "true"
|
||||
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION
|
||||
|
||||
interface <caret>Base<T : Any>
|
||||
@@ -0,0 +1,5 @@
|
||||
// "Implement interface" "true"
|
||||
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION
|
||||
|
||||
interface Base<T : Any>
|
||||
class BaseImpl<T : Any> : Base<T>
|
||||
@@ -0,0 +1,4 @@
|
||||
// "Implement interface" "true"
|
||||
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION
|
||||
|
||||
interface <caret>Base<out T>
|
||||
@@ -0,0 +1,5 @@
|
||||
// "Implement interface" "true"
|
||||
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION
|
||||
|
||||
interface Base<out T>
|
||||
class BaseImpl<out T> : Base<T>
|
||||
@@ -0,0 +1,4 @@
|
||||
// "Implement interface" "true"
|
||||
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION
|
||||
|
||||
interface <caret>Base<T> where T : Any
|
||||
@@ -0,0 +1,5 @@
|
||||
// "Implement interface" "true"
|
||||
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION
|
||||
|
||||
interface Base<T> where T : Any
|
||||
class BaseImpl<T> : Base<T> where T : Any
|
||||
@@ -0,0 +1,4 @@
|
||||
// "Create subclass" "true"
|
||||
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION
|
||||
|
||||
open class <caret>Base<T : Any, L : List<T>>
|
||||
@@ -0,0 +1,5 @@
|
||||
// "Create subclass" "true"
|
||||
// SHOULD_BE_AVAILABLE_AFTER_EXECUTION
|
||||
|
||||
open class Base<T : Any, L : List<T>>
|
||||
class BaseImpl<T : Any, L : List<T>> : Base<T, L>()
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user