Intentions: 'Implement abstract member' (Kotlin -> Kotlin)

#KT-8467 In Progress
This commit is contained in:
Alexey Sedunov
2015-12-18 15:07:16 +03:00
parent 123b813073
commit 03641ffbee
51 changed files with 889 additions and 9 deletions
@@ -22,7 +22,6 @@ import com.intellij.navigation.ItemPresentationProviders
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiWhiteSpace
import com.intellij.psi.impl.CheckUtil
import com.intellij.psi.impl.source.codeStyle.CodeEditUtil
import com.intellij.psi.stubs.IStubElementType
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.lexer.KtTokens
@@ -64,8 +63,6 @@ abstract public class KtClassOrObject :
public fun getBody(): KtClassBody? = getStubOrPsiChild(KtStubElementTypes.CLASS_BODY)
public fun getOrCreateBody(): KtClassBody = getBody() ?: add(KtPsiFactory(this).createEmptyClassBody()) as KtClassBody
public fun addDeclaration(declaration: KtDeclaration): KtDeclaration {
val body = getOrCreateBody()
val anchor = PsiTreeUtil.skipSiblingsBackward(body.rBrace ?: body.getLastChild()!!, javaClass<PsiWhiteSpace>())
@@ -117,3 +114,11 @@ abstract public class KtClassOrObject :
}
}
}
public fun KtClassOrObject.getOrCreateBody(): KtClassBody {
getBody()?.let { return it }
val newBody = KtPsiFactory(this).createEmptyClassBody()
if (this is KtEnumEntry) return addAfter(newBody, initializerList ?: nameIdentifier) as KtClassBody
return add(newBody) as KtClassBody
}
@@ -27,7 +27,9 @@ import com.intellij.psi.util.PsiTreeUtil
import com.intellij.util.SmartList
import org.jetbrains.kotlin.idea.util.ShortenReferences
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.allChildren
import org.jetbrains.kotlin.psi.psiUtil.siblings
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.utils.ifEmpty
@@ -156,6 +158,22 @@ public fun <T : KtDeclaration> insertMembersAfter(
var afterAnchor = anchor ?: findInsertAfterAnchor(editor, body) ?: return@runWriteAction emptyList()
val insertedMembers = members.mapTo(SmartList<T>()) {
if (classOrObject is KtClass && classOrObject.isEnum()) {
val enumEntries = classOrObject.declarations.filterIsInstance<KtEnumEntry>()
val bound = (enumEntries.lastOrNull() ?: classOrObject.allChildren.firstOrNull { it.node.elementType == KtTokens.SEMICOLON })
if (it !is KtEnumEntry) {
if (bound != null && afterAnchor.startOffset <= bound.startOffset) {
afterAnchor = bound
}
}
else if (bound == null && body.declarations.isNotEmpty()) {
afterAnchor = body.lBrace!!
}
else if (bound != null && afterAnchor.startOffset >= bound.startOffset) {
afterAnchor = bound.prevSibling!!
}
}
@Suppress("UNCHECKED_CAST")
(body.addAfter(it, afterAnchor) as T).apply { afterAnchor = this }
}
@@ -91,7 +91,7 @@ public abstract class OverrideImplementMembersHandler : LanguageCodeInsightActio
override fun startInWriteAction(): Boolean = false
companion object {
public fun generateMembers(editor: Editor, classOrObject: KtClassOrObject, selectedElements: Collection<OverrideMemberChooserObject>) {
public fun generateMembers(editor: Editor?, classOrObject: KtClassOrObject, selectedElements: Collection<OverrideMemberChooserObject>) {
val project = classOrObject.project
insertMembersAfter(editor, classOrObject, selectedElements.map { it.generateMember(project) })
}
@@ -0,0 +1,9 @@
interface A {
fun foo(): Int
}
class B : A {
<spot>override fun foo(): Int {
throw UnsupportedOperationException()
}</spot>
}
@@ -0,0 +1,7 @@
interface A {
<spot>fun foo(): Int</spot>
}
class B : A {
}
@@ -0,0 +1,5 @@
<html>
<body>
This intention searches for all classes that can implement selected abstract member, and creates default implementation there.
</body>
</html>
+5
View File
@@ -1110,6 +1110,11 @@
<category>Kotlin</category>
</intentionAction>
<intentionAction>
<className>org.jetbrains.kotlin.idea.intentions.ImplementAbstractMemberIntention</className>
<category>Kotlin</category>
</intentionAction>
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.ObjectLiteralToLambdaInspection"
displayName="Convert object literal to lambda"
groupName="Kotlin"
@@ -21,6 +21,7 @@ import com.intellij.openapi.util.TextRange
import com.intellij.psi.impl.source.codeStyle.PreFormatProcessor
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.allChildren
import org.jetbrains.kotlin.utils.addToStdlib.lastIsInstanceOrNull
class KotlinPreFormatProcessor : PreFormatProcessor {
@@ -34,7 +35,8 @@ class KotlinPreFormatProcessor : PreFormatProcessor {
if (!klass.isEnum()) return
val lastEntry = klass.declarations.lastIsInstanceOrNull<KtEnumEntry>()
if (KtPsiUtil.skipTrailingWhitespacesAndComments(lastEntry ?: classBody.firstChild)?.node?.elementType == KtTokens.SEMICOLON) return
if (lastEntry != null && lastEntry.allChildren.any { it.node.elementType == KtTokens.SEMICOLON }) return
if (lastEntry == null && classBody.allChildren.any { it.node.elementType == KtTokens.SEMICOLON }) return
val semicolon = KtPsiFactory(klass).createSemicolon()
classBody.addAfter(semicolon, lastEntry)
@@ -0,0 +1,215 @@
/*
* Copyright 2010-2015 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.CodeInsightBundle
import com.intellij.codeInsight.FileModificationService
import com.intellij.ide.util.PsiClassListCellRenderer
import com.intellij.ide.util.PsiElementListCellRenderer
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.ui.popup.PopupChooserBuilder
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement
import com.intellij.ui.components.JBList
import com.intellij.util.IncorrectOperationException
import org.jetbrains.kotlin.asJava.KtLightClass
import org.jetbrains.kotlin.asJava.KtLightClassForExplicitDeclaration
import org.jetbrains.kotlin.asJava.toLightClass
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideImplementMembersHandler
import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMemberChooserObject
import org.jetbrains.kotlin.idea.refactoring.canRefactor
import org.jetbrains.kotlin.idea.refactoring.isInterfaceClass
import org.jetbrains.kotlin.idea.refactoring.runSynchronouslyWithProgress
import org.jetbrains.kotlin.idea.search.declarationsSearch.HierarchySearchRequest
import org.jetbrains.kotlin.idea.search.declarationsSearch.searchInheritors
import org.jetbrains.kotlin.idea.util.application.executeCommand
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.types.TypeSubstitutor
import org.jetbrains.kotlin.types.substitutions.getTypeSubstitutor
import org.jetbrains.kotlin.util.findCallableMemberBySignature
import org.jetbrains.kotlin.utils.addToStdlib.singletonList
import java.util.*
import javax.swing.ListSelectionModel
class ImplementAbstractMemberIntention :
SelfTargetingRangeIntention<KtNamedDeclaration>(KtNamedDeclaration::class.java, "", "Implement abstract member") {
companion object {
private val LOG = Logger.getInstance("#${ImplementAbstractMemberIntention::class.java.canonicalName}")
}
private fun isAbstract(element: KtNamedDeclaration): Boolean {
if (element.hasModifier(KtTokens.ABSTRACT_KEYWORD)) return true
if (!(element.containingClassOrObject?.isInterfaceClass() ?: false)) return false
return when (element) {
is KtProperty -> element.initializer == null && element.delegate == null && element.accessors.isEmpty()
is KtNamedFunction -> !element.hasBody()
else -> false
}
}
private fun findExistingImplementation(
subClass: ClassDescriptor,
superMember: CallableMemberDescriptor
): CallableMemberDescriptor? {
val superClass = superMember.containingDeclaration as? ClassDescriptor ?: return null
val substitutor = getTypeSubstitutor(superClass.defaultType, subClass.defaultType) ?: TypeSubstitutor.EMPTY
val subMember = subClass.findCallableMemberBySignature(superMember.substitute(substitutor) as CallableMemberDescriptor)
if (subMember?.kind?.isReal ?: false) return subMember else return null
}
private fun findClassesToProcess(member: KtNamedDeclaration): Sequence<KtClassOrObject> {
val baseClass = member.containingClassOrObject as? KtClass ?: return emptySequence()
val memberDescriptor = member.resolveToDescriptorIfAny() as? CallableMemberDescriptor ?: return emptySequence()
fun acceptSubClass(classOrObject: KtClassOrObject): Boolean {
val classDescriptor = classOrObject.resolveToDescriptorIfAny() as? ClassDescriptor ?: return false
return classDescriptor.kind != ClassKind.INTERFACE && findExistingImplementation(classDescriptor, memberDescriptor) == null
}
if (baseClass.isEnum()) {
return baseClass.declarations
.asSequence()
.filterIsInstance<KtEnumEntry>()
.filter(::acceptSubClass)
}
return HierarchySearchRequest(baseClass, baseClass.useScope, false)
.searchInheritors()
.asSequence()
.mapNotNull { (it as? KtLightClassForExplicitDeclaration)?.getOrigin() }
.filter(::acceptSubClass)
}
override fun applicabilityRange(element: KtNamedDeclaration): TextRange? {
if (!isAbstract(element)) return null
text = when(element) {
is KtProperty -> "Implement abstract property"
is KtNamedFunction -> "Implement abstract function"
else -> return null
}
if (!findClassesToProcess(element).any()) return null
return element.nameIdentifier?.textRange
}
private fun implementInClass(member: KtNamedDeclaration, targetClasses: List<PsiElement>) {
val project = member.project
project.executeCommand(CodeInsightBundle.message("intention.implement.abstract.method.command.name")) {
if (!FileModificationService.getInstance().preparePsiElementsForWrite(targetClasses)) return@executeCommand
runWriteAction {
for (targetClass in targetClasses) {
try {
val subClass = (targetClass as? KtLightClass)?.getOrigin() ?: targetClass as? KtClassOrObject ?: continue
val subClassDescriptor = subClass.resolveToDescriptorIfAny() as? ClassDescriptor ?: continue
val superMemberDescriptor = member.resolveToDescriptorIfAny() as? CallableMemberDescriptor ?: continue
val superClassDescriptor = superMemberDescriptor.containingDeclaration as? ClassDescriptor ?: continue
val substitutor = getTypeSubstitutor(superClassDescriptor.defaultType, subClassDescriptor.defaultType)
?: TypeSubstitutor.EMPTY
val descriptorToImplement = superMemberDescriptor.substitute(substitutor) as CallableMemberDescriptor
val chooserObject = OverrideMemberChooserObject.create(project,
descriptorToImplement,
descriptorToImplement,
OverrideMemberChooserObject.BodyType.EMPTY)
OverrideImplementMembersHandler.generateMembers(null, subClass, chooserObject.singletonList())
}
catch(e: IncorrectOperationException) {
LOG.error(e)
}
}
}
}
}
private class ClassRenderer : PsiElementListCellRenderer<PsiElement>() {
private val psiClassRenderer = PsiClassListCellRenderer()
override fun getComparator(): Comparator<PsiElement> {
val baseComparator = psiClassRenderer.comparator
return Comparator { o1, o2 ->
when {
o1 is KtEnumEntry && o2 is KtEnumEntry -> o1.name!!.compareTo(o2.name!!)
o1 is KtEnumEntry -> -1
o2 is KtEnumEntry -> 1
o1 is PsiClass && o2 is PsiClass -> baseComparator.compare(o1 as PsiClass, o2 as PsiClass)
else -> 0
}
}
}
override fun getIconFlags() = 0
override fun getElementText(element: PsiElement?): String? {
return when (element) {
is KtEnumEntry -> element.name
is PsiClass -> psiClassRenderer.getElementText(element)
else -> null
}
}
override fun getContainerText(element: PsiElement?, name: String?): String? {
return when (element) {
is KtEnumEntry -> element.containingClassOrObject?.fqName?.asString()
is PsiClass -> PsiClassListCellRenderer.getContainerTextStatic(element)
else -> null
}
}
}
override fun applyTo(element: KtNamedDeclaration, editor: Editor) {
val project = element.project
val classesToProcess = project.runSynchronouslyWithProgress(
CodeInsightBundle.message("intention.implement.abstract.method.searching.for.descendants.progress"),
true
) { findClassesToProcess(element).map { it.toLightClass() ?: it }.toList() } ?: return
if (classesToProcess.isEmpty()) return
classesToProcess.singleOrNull()?.let { return implementInClass(element, it.singletonList()) }
if (ApplicationManager.getApplication().isUnitTestMode) return implementInClass(element, classesToProcess)
val renderer = ClassRenderer()
val list = JBList(classesToProcess.sortedWith(renderer.comparator)).apply {
selectionMode = ListSelectionModel.MULTIPLE_INTERVAL_SELECTION
cellRenderer = renderer
}
val builder = PopupChooserBuilder(list)
renderer.installSpeedSearch(builder)
builder
.setTitle(CodeInsightBundle.message("intention.implement.abstract.method.class.chooser.title"))
.setItemChoosenCallback {
val index = list.selectedIndex
if (index < 0) return@setItemChoosenCallback
@Suppress("UNCHECKED_CAST")
implementInClass(element, list.selectedValues.toList() as List<KtClassOrObject>)
}
.createPopup()
.showInBestPositionFor(editor)
}
}
@@ -34,10 +34,7 @@ import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.util.ShortenReferences
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.types.typeUtil.supertypes
@@ -0,0 +1 @@
org.jetbrains.kotlin.idea.intentions.ImplementAbstractMemberIntention
@@ -0,0 +1,9 @@
// WITH_RUNTIME
// DISABLE-ERRORS
interface T<X> {
fun <caret>foo(x: X): X
}
enum class E : T<Int> {
A, B, C
}
@@ -0,0 +1,13 @@
// WITH_RUNTIME
// DISABLE-ERRORS
interface T<X> {
fun <caret>foo(x: X): X
}
enum class E : T<Int> {
A, B, C;
override fun foo(x: Int): Int {
throw UnsupportedOperationException()
}
}
@@ -0,0 +1,9 @@
// WITH_RUNTIME
// DISABLE-ERRORS
interface T<X> {
fun <caret>foo(x: X): X
}
enum class E : T<Int> {
A, B, C;
}
@@ -0,0 +1,13 @@
// WITH_RUNTIME
// DISABLE-ERRORS
interface T<X> {
fun <caret>foo(x: X): X
}
enum class E : T<Int> {
A, B, C;
override fun foo(x: Int): Int {
throw UnsupportedOperationException()
}
}
@@ -0,0 +1,13 @@
// WITH_RUNTIME
// DISABLE-ERRORS
interface T<X> {
fun <caret>foo(x: X): X
}
enum class E : T<Int> {
A, B, C;
val bar = 1
fun baz() = 2
}
@@ -0,0 +1,17 @@
// WITH_RUNTIME
// DISABLE-ERRORS
interface T<X> {
fun <caret>foo(x: X): X
}
enum class E : T<Int> {
A, B, C;
override fun foo(x: Int): Int {
throw UnsupportedOperationException()
}
val bar = 1
fun baz() = 2
}
@@ -0,0 +1,7 @@
// WITH_RUNTIME
//DISABLE-ERRORS
enum class E {
A, B, C;
abstract fun <caret>foo(x: Int): Int
}
@@ -0,0 +1,19 @@
// WITH_RUNTIME
//DISABLE-ERRORS
enum class E {
A {
override fun foo(x: Int): Int {
throw UnsupportedOperationException()
}
}, B {
override fun foo(x: Int): Int {
throw UnsupportedOperationException()
}
}, C {
override fun foo(x: Int): Int {
throw UnsupportedOperationException()
}
};
abstract fun <caret>foo(x: Int): Int
}
@@ -0,0 +1,7 @@
// WITH_RUNTIME
//DISABLE-ERRORS
enum class E(n: Int) {
A(1), B(2), C(3);
abstract fun <caret>foo(x: Int): Int
}
@@ -0,0 +1,19 @@
// WITH_RUNTIME
//DISABLE-ERRORS
enum class E(n: Int) {
A(1) {
override fun foo(x: Int): Int {
throw UnsupportedOperationException()
}
}, B(2) {
override fun foo(x: Int): Int {
throw UnsupportedOperationException()
}
}, C(3) {
override fun foo(x: Int): Int {
throw UnsupportedOperationException()
}
};
abstract fun <caret>foo(x: Int): Int
}
@@ -0,0 +1,23 @@
// WITH_RUNTIME
// DISABLE-ERRORS
interface T<X> {
fun <caret>foo(x: X): X
}
class U : T<String> {
}
class V : T<Int> {
}
class Z : T<Int> by V() {
}
class W : T<Boolean> {
override fun foo(x: Boolean): Boolean {
throw UnsupportedOperationException()
}
}
@@ -0,0 +1,29 @@
// WITH_RUNTIME
// DISABLE-ERRORS
interface T<X> {
fun <caret>foo(x: X): X
}
class U : T<String> {
override fun foo(x: String): String {
throw UnsupportedOperationException()
}
}
class V : T<Int> {
override fun foo(x: Int): Int {
throw UnsupportedOperationException()
}
}
class Z : T<Int> by V() {
}
class W : T<Boolean> {
override fun foo(x: Boolean): Boolean {
throw UnsupportedOperationException()
}
}
@@ -0,0 +1,5 @@
// IS_APPLICABLE: false
// ERROR: Abstract function 'foo' in non-abstract class 'A'
class A {
abstract fun <caret>foo(): Int
}
@@ -0,0 +1,5 @@
// IS_APPLICABLE: false
// ERROR: Abstract function 'foo' in non-abstract class 'A'
object A {
abstract fun <caret>foo(): Int
}
@@ -0,0 +1,17 @@
// IS_APPLICABLE: false
// ERROR: Class 'C' must be declared abstract or implement abstract base class member public abstract fun foo(): kotlin.Int defined in B
interface A {
fun <caret>foo(): Int
}
class X : A {
override fun foo() = 1
}
abstract class B : A {
abstract override fun foo(): Int
}
class C: B() {
}
@@ -0,0 +1,4 @@
// IS_APPLICABLE: false
interface A {
fun <caret>foo(): Int
}
@@ -0,0 +1,4 @@
// IS_APPLICABLE: false
open class A {
fun <caret>foo() = 1
}
@@ -0,0 +1,4 @@
// IS_APPLICABLE: false
interface A {
fun <caret>foo() = 1
}
@@ -0,0 +1,5 @@
// IS_APPLICABLE: false
// ERROR: Function 'foo' without a body must be abstract
open class A {
fun <caret>foo(): Int
}
@@ -0,0 +1 @@
org.jetbrains.kotlin.idea.intentions.ImplementAbstractMemberIntention
@@ -0,0 +1,9 @@
// WITH_RUNTIME
// DISABLE-ERRORS
interface T<X> {
val <caret>foo: X
}
enum class E : T<Int> {
A, B, C
}
@@ -0,0 +1,12 @@
// WITH_RUNTIME
// DISABLE-ERRORS
interface T<X> {
val <caret>foo: X
}
enum class E : T<Int> {
A, B, C;
override val foo: Int
get() = throw UnsupportedOperationException()
}
@@ -0,0 +1,9 @@
// WITH_RUNTIME
// DISABLE-ERRORS
interface T<X> {
val <caret>foo: X
}
enum class E : T<Int> {
A, B, C;
}
@@ -0,0 +1,12 @@
// WITH_RUNTIME
// DISABLE-ERRORS
interface T<X> {
val <caret>foo: X
}
enum class E : T<Int> {
A, B, C;
override val foo: Int
get() = throw UnsupportedOperationException()
}
@@ -0,0 +1,13 @@
// WITH_RUNTIME
// DISABLE-ERRORS
interface T<X> {
val <caret>foo: X
}
enum class E : T<Int> {
A, B, C;
val bar = 1
fun baz() = 2
}
@@ -0,0 +1,16 @@
// WITH_RUNTIME
// DISABLE-ERRORS
interface T<X> {
val <caret>foo: X
}
enum class E : T<Int> {
A, B, C;
override val foo: Int
get() = throw UnsupportedOperationException()
val bar = 1
fun baz() = 2
}
@@ -0,0 +1,7 @@
// WITH_RUNTIME
//DISABLE-ERRORS
enum class E {
A, B, C;
abstract val <caret>foo: Int
}
@@ -0,0 +1,16 @@
// WITH_RUNTIME
//DISABLE-ERRORS
enum class E {
A {
override val foo: Int
get() = throw UnsupportedOperationException()
}, B {
override val foo: Int
get() = throw UnsupportedOperationException()
}, C {
override val foo: Int
get() = throw UnsupportedOperationException()
};
abstract val <caret>foo: Int
}
@@ -0,0 +1,7 @@
// WITH_RUNTIME
//DISABLE-ERRORS
enum class E(n: Int) {
A(1), B(2), C(3);
abstract val <caret>foo: Int
}
@@ -0,0 +1,16 @@
// WITH_RUNTIME
//DISABLE-ERRORS
enum class E(n: Int) {
A(1) {
override val foo: Int
get() = throw UnsupportedOperationException()
}, B(2) {
override val foo: Int
get() = throw UnsupportedOperationException()
}, C(3) {
override val foo: Int
get() = throw UnsupportedOperationException()
};
abstract val <caret>foo: Int
}
@@ -0,0 +1,22 @@
// WITH_RUNTIME
// DISABLE-ERRORS
interface T<X> {
val <caret>foo: X
}
class U : T<String> {
}
class V : T<Int> {
}
class Z : T<Int> by V() {
}
class W : T<Boolean> {
override val foo: Boolean
get() = throw UnsupportedOperationException()
}
@@ -0,0 +1,26 @@
// WITH_RUNTIME
// DISABLE-ERRORS
interface T<X> {
val <caret>foo: X
}
class U : T<String> {
override val foo: String
get() = throw UnsupportedOperationException()
}
class V : T<Int> {
override val foo: Int
get() = throw UnsupportedOperationException()
}
class Z : T<Int> by V() {
}
class W : T<Boolean> {
override val foo: Boolean
get() = throw UnsupportedOperationException()
}
@@ -0,0 +1,5 @@
// IS_APPLICABLE: false
// ERROR: Abstract property 'foo' in non-abstract class 'A'
class A {
abstract val <caret>foo: Int
}
@@ -0,0 +1,5 @@
// IS_APPLICABLE: false
// ERROR: Abstract property 'foo' in non-abstract class 'A'
object A {
abstract val <caret>foo: Int
}
@@ -0,0 +1,17 @@
// IS_APPLICABLE: false
// ERROR: Class 'C' must be declared abstract or implement abstract base class member public abstract val foo: kotlin.Int defined in B
interface A {
val <caret>foo: Int
}
class X : A {
override val foo = 1
}
abstract class B : A {
abstract override val foo: Int
}
class C: B() {
}
@@ -0,0 +1,4 @@
// IS_APPLICABLE: false
interface A {
val <caret>foo: Int
}
@@ -0,0 +1,4 @@
// IS_APPLICABLE: false
open class A {
val <caret>foo = 1
}
@@ -0,0 +1,5 @@
// IS_APPLICABLE: false
// ERROR: Property must be initialized or be abstract
open class A {
val <caret>foo: Int
}
@@ -0,0 +1,5 @@
// IS_APPLICABLE: false
interface A {
val <caret>foo: Int
get() = 1
}
@@ -5230,6 +5230,189 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
}
}
@TestMetadata("idea/testData/intentions/implementAbstractMember")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class ImplementAbstractMember extends AbstractIntentionTest {
public void testAllFilesPresentInImplementAbstractMember() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/implementAbstractMember"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true);
}
@TestMetadata("idea/testData/intentions/implementAbstractMember/function")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Function extends AbstractIntentionTest {
public void testAllFilesPresentInFunction() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/implementAbstractMember/function"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true);
}
@TestMetadata("enumClass.kt")
public void testEnumClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/implementAbstractMember/function/enumClass.kt");
doTest(fileName);
}
@TestMetadata("enumClassWithSemicolon.kt")
public void testEnumClassWithSemicolon() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/implementAbstractMember/function/enumClassWithSemicolon.kt");
doTest(fileName);
}
@TestMetadata("enumClassWithSemicolonAndMembers.kt")
public void testEnumClassWithSemicolonAndMembers() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/implementAbstractMember/function/enumClassWithSemicolonAndMembers.kt");
doTest(fileName);
}
@TestMetadata("enumEntries.kt")
public void testEnumEntries() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/implementAbstractMember/function/enumEntries.kt");
doTest(fileName);
}
@TestMetadata("enumEntriesWithArgs.kt")
public void testEnumEntriesWithArgs() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/implementAbstractMember/function/enumEntriesWithArgs.kt");
doTest(fileName);
}
@TestMetadata("implementAll.kt")
public void testImplementAll() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/implementAbstractMember/function/implementAll.kt");
doTest(fileName);
}
@TestMetadata("inFinalClass.kt")
public void testInFinalClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/implementAbstractMember/function/inFinalClass.kt");
doTest(fileName);
}
@TestMetadata("inObject.kt")
public void testInObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/implementAbstractMember/function/inObject.kt");
doTest(fileName);
}
@TestMetadata("noDirectOverridesNeeded.kt")
public void testNoDirectOverridesNeeded() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/implementAbstractMember/function/noDirectOverridesNeeded.kt");
doTest(fileName);
}
@TestMetadata("noInheritors.kt")
public void testNoInheritors() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/implementAbstractMember/function/noInheritors.kt");
doTest(fileName);
}
@TestMetadata("notAbstractInClass.kt")
public void testNotAbstractInClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/implementAbstractMember/function/notAbstractInClass.kt");
doTest(fileName);
}
@TestMetadata("notAbstractInInterface.kt")
public void testNotAbstractInInterface() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/implementAbstractMember/function/notAbstractInInterface.kt");
doTest(fileName);
}
@TestMetadata("notAbstractNoBodyInClass.kt")
public void testNotAbstractNoBodyInClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/implementAbstractMember/function/notAbstractNoBodyInClass.kt");
doTest(fileName);
}
}
@TestMetadata("idea/testData/intentions/implementAbstractMember/property")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Property extends AbstractIntentionTest {
public void testAllFilesPresentInProperty() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/intentions/implementAbstractMember/property"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), true);
}
@TestMetadata("enumClass.kt")
public void testEnumClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/implementAbstractMember/property/enumClass.kt");
doTest(fileName);
}
@TestMetadata("enumClassWithSemicolon.kt")
public void testEnumClassWithSemicolon() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/implementAbstractMember/property/enumClassWithSemicolon.kt");
doTest(fileName);
}
@TestMetadata("enumClassWithSemicolonAndMembers.kt")
public void testEnumClassWithSemicolonAndMembers() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/implementAbstractMember/property/enumClassWithSemicolonAndMembers.kt");
doTest(fileName);
}
@TestMetadata("enumEntries.kt")
public void testEnumEntries() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/implementAbstractMember/property/enumEntries.kt");
doTest(fileName);
}
@TestMetadata("enumEntriesWithArgs.kt")
public void testEnumEntriesWithArgs() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/implementAbstractMember/property/enumEntriesWithArgs.kt");
doTest(fileName);
}
@TestMetadata("implementAll.kt")
public void testImplementAll() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/implementAbstractMember/property/implementAll.kt");
doTest(fileName);
}
@TestMetadata("inFinalClass.kt")
public void testInFinalClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/implementAbstractMember/property/inFinalClass.kt");
doTest(fileName);
}
@TestMetadata("inObject.kt")
public void testInObject() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/implementAbstractMember/property/inObject.kt");
doTest(fileName);
}
@TestMetadata("noDirectOverridesNeeded.kt")
public void testNoDirectOverridesNeeded() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/implementAbstractMember/property/noDirectOverridesNeeded.kt");
doTest(fileName);
}
@TestMetadata("noInheritors.kt")
public void testNoInheritors() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/implementAbstractMember/property/noInheritors.kt");
doTest(fileName);
}
@TestMetadata("notAbstractInClass.kt")
public void testNotAbstractInClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/implementAbstractMember/property/notAbstractInClass.kt");
doTest(fileName);
}
@TestMetadata("notAbstractNoBodyInClass.kt")
public void testNotAbstractNoBodyInClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/implementAbstractMember/property/notAbstractNoBodyInClass.kt");
doTest(fileName);
}
@TestMetadata("notAbstractWithGetterInInterface.kt")
public void testNotAbstractWithGetterInInterface() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/implementAbstractMember/property/notAbstractWithGetterInInterface.kt");
doTest(fileName);
}
}
}
@TestMetadata("idea/testData/intentions/importAllMembers")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)