From 377201bbcd481f0f2b046107278c0c9fdaafcdba Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Fri, 7 Aug 2015 20:11:21 +0300 Subject: [PATCH] KT-8716 Exception on attempt to implement function #KT-8716 Fixed --- .../ImplementMethodsHandler.kt | 2 +- .../OverrideMemberChooserObject.kt | 47 +++++++++++++++++-- .../OverrideMethodsHandler.kt | 2 +- .../util/DescriptorMemberChooserObject.kt | 18 +++---- .../ImplementFunctionType.kt | 3 ++ .../implementFunctionType.kt.after | 5 ++ .../AbstractOverrideImplementTest.kt | 2 +- .../codeInsight/OverrideImplementTest.java | 4 ++ 8 files changed, 66 insertions(+), 17 deletions(-) create mode 100644 idea/testData/codeInsight/overrideImplement/ImplementFunctionType.kt create mode 100644 idea/testData/codeInsight/overrideImplement/implementFunctionType.kt.after diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/ImplementMethodsHandler.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/ImplementMethodsHandler.kt index e6772fe81f3..c79ffa528fa 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/ImplementMethodsHandler.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/ImplementMethodsHandler.kt @@ -27,7 +27,7 @@ import org.jetbrains.kotlin.resolve.OverrideResolver public class ImplementMethodsHandler : OverrideImplementMethodsHandler(), IntentionAction { override fun collectMethodsToGenerate(descriptor: ClassDescriptor, project: Project): Collection { return OverrideResolver.getMissingImplementations(descriptor) - .map { OverrideMemberChooserObject(project, it, it) } + .map { OverrideMemberChooserObject.create(project, it, it) } } override fun getChooserTitle() = "Implement Members" diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/OverrideMemberChooserObject.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/OverrideMemberChooserObject.kt index 9a3a06b2509..4a46bbbef1b 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/OverrideMemberChooserObject.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/OverrideMemberChooserObject.kt @@ -16,13 +16,50 @@ package org.jetbrains.kotlin.idea.core.overrideImplement +import com.intellij.codeInsight.generation.ClassMember +import com.intellij.codeInsight.generation.MemberChooserObject +import com.intellij.codeInsight.generation.MemberChooserObjectBase import com.intellij.openapi.project.Project +import com.intellij.psi.PsiElement import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor +import org.jetbrains.kotlin.descriptors.ClassifierDescriptor import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde import org.jetbrains.kotlin.idea.core.util.DescriptorMemberChooserObject -class OverrideMemberChooserObject( - project: Project, - val member: CallableMemberDescriptor, - val immediateSuper: CallableMemberDescriptor -) : DescriptorMemberChooserObject(DescriptorToSourceUtilsIde.getAnyDeclaration(project, member)!!, member) \ No newline at end of file +interface OverrideMemberChooserObject : ClassMember { + val descriptor: CallableMemberDescriptor + val immediateSuper: CallableMemberDescriptor + + companion object { + fun create(project: Project, descriptor: CallableMemberDescriptor, immediateSuper: CallableMemberDescriptor): OverrideMemberChooserObject { + val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, descriptor) + if (declaration != null) { + return WithDeclaration(descriptor, declaration, immediateSuper) + } + else { + return WithoutDeclaration(descriptor, immediateSuper) + } + } + + private class WithDeclaration( + descriptor: CallableMemberDescriptor, + declaration: PsiElement, + override val immediateSuper: CallableMemberDescriptor + ) : DescriptorMemberChooserObject(declaration, descriptor), OverrideMemberChooserObject { + + override val descriptor: CallableMemberDescriptor + get() = super.descriptor as CallableMemberDescriptor + } + + private class WithoutDeclaration( + override val descriptor: CallableMemberDescriptor, + override val immediateSuper: CallableMemberDescriptor + ) : MemberChooserObjectBase(DescriptorMemberChooserObject.getText(descriptor), DescriptorMemberChooserObject.getIcon(null, descriptor)), OverrideMemberChooserObject { + + override fun getParentNodeDelegate(): MemberChooserObject? { + val parentClassifier = descriptor.containingDeclaration as? ClassifierDescriptor ?: return null + return MemberChooserObjectBase(DescriptorMemberChooserObject.getText(parentClassifier), DescriptorMemberChooserObject.getIcon(null, parentClassifier)) + } + } + } +} diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/OverrideMethodsHandler.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/OverrideMethodsHandler.kt index 564bdc8de00..4be7e8ca8b8 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/OverrideMethodsHandler.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/OverrideMethodsHandler.kt @@ -59,7 +59,7 @@ public class OverrideMethodsHandler : OverrideImplementMethodsHandler() { else { immediateSupers.singleOrNull { (it.containingDeclaration as? ClassDescriptor)?.kind == ClassKind.CLASS } ?: immediateSupers.first() } - result.add(OverrideMemberChooserObject(project, realSuper, immediateSuperToUse)) + result.add(OverrideMemberChooserObject.create(project, realSuper, immediateSuperToUse)) } } } diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/util/DescriptorMemberChooserObject.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/util/DescriptorMemberChooserObject.kt index ea89d44159b..f0348352251 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/util/DescriptorMemberChooserObject.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/util/DescriptorMemberChooserObject.kt @@ -40,7 +40,7 @@ import javax.swing.Icon public open class DescriptorMemberChooserObject( psiElement: PsiElement, - public val descriptor: DeclarationDescriptor + public open val descriptor: DeclarationDescriptor ) : PsiElementMemberChooserObject(psiElement, DescriptorMemberChooserObject.getText(descriptor), DescriptorMemberChooserObject.getIcon(psiElement, descriptor)), ClassMemberWithElement { override fun getParentNodeDelegate(): MemberChooserObject { @@ -74,29 +74,29 @@ public open class DescriptorMemberChooserObject( nameShortness = NameShortness.SHORT } - private fun getText(descriptor: DeclarationDescriptor): String { + public fun getText(descriptor: DeclarationDescriptor): String { return if (descriptor is ClassDescriptor) descriptor.fqNameSafe.render() else MEMBER_RENDERER.render(descriptor) } - private fun getIcon(element: PsiElement, descriptor: DeclarationDescriptor): Icon { - if (element.isValid) { - val isClass = element is PsiClass || element is JetClass + public fun getIcon(declaration: PsiElement?, descriptor: DeclarationDescriptor): Icon { + if (declaration != null && declaration.isValid) { + val isClass = declaration is PsiClass || declaration is JetClass val flags = if (isClass) 0 else Iconable.ICON_FLAG_VISIBILITY - if (element is JetDeclaration) { + if (declaration is JetDeclaration) { // kotlin declaration // visibility and abstraction better detect by a descriptor - return JetDescriptorIconProvider.getIcon(descriptor, element, flags) + return JetDescriptorIconProvider.getIcon(descriptor, declaration, flags) } else { // it is better to show java icons for java code - return element.getIcon(flags) + return declaration.getIcon(flags) } } else { - return JetDescriptorIconProvider.getIcon(descriptor, element, 0) + return JetDescriptorIconProvider.getIcon(descriptor, declaration, 0) } } } diff --git a/idea/testData/codeInsight/overrideImplement/ImplementFunctionType.kt b/idea/testData/codeInsight/overrideImplement/ImplementFunctionType.kt new file mode 100644 index 00000000000..0db3d0cfb59 --- /dev/null +++ b/idea/testData/codeInsight/overrideImplement/ImplementFunctionType.kt @@ -0,0 +1,3 @@ +class C : (String) -> Boolean { + +} \ No newline at end of file diff --git a/idea/testData/codeInsight/overrideImplement/implementFunctionType.kt.after b/idea/testData/codeInsight/overrideImplement/implementFunctionType.kt.after new file mode 100644 index 00000000000..06ac13a15a7 --- /dev/null +++ b/idea/testData/codeInsight/overrideImplement/implementFunctionType.kt.after @@ -0,0 +1,5 @@ +class C : (String) -> Boolean { + override fun invoke(p1: String): Boolean { + throw UnsupportedOperationException() + } +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractOverrideImplementTest.kt b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractOverrideImplementTest.kt index 5171e44d481..d3776f1a84d 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractOverrideImplementTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractOverrideImplementTest.kt @@ -146,7 +146,7 @@ public abstract class AbstractOverrideImplementTest : JetLightCodeInsightFixture val classOrObject = PsiTreeUtil.getParentOfType(elementAtCaret, javaClass()) ?: error("Caret should be inside class or object") - val chooserObjects = handler.collectMethodsToGenerate(classOrObject).sortBy { it.member.name.asString() + " in " + it.immediateSuper.containingDeclaration.name.asString() } + val chooserObjects = handler.collectMethodsToGenerate(classOrObject).sortBy { it.descriptor.name.asString() + " in " + it.immediateSuper.containingDeclaration.name.asString() } performGenerateCommand(classOrObject, chooserObjects) } diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/OverrideImplementTest.java b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/OverrideImplementTest.java index fbf38290579..e51a4b512d0 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/OverrideImplementTest.java +++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/OverrideImplementTest.java @@ -214,4 +214,8 @@ public final class OverrideImplementTest extends AbstractOverrideImplementTest { public void testAmbiguousSuper() { doMultiOverrideFileTest(); } + + public void testImplementFunctionType() { + doMultiImplementFileTest(); + } }