Override members does not generate qualified super when not needed

This commit is contained in:
Valentin Kipyatkov
2015-08-25 20:32:07 +03:00
parent dd6702b832
commit 40638de67c
28 changed files with 92 additions and 63 deletions
@@ -27,7 +27,7 @@ import org.jetbrains.kotlin.resolve.OverrideResolver
public class ImplementMembersHandler : OverrideImplementMembersHandler(), IntentionAction { public class ImplementMembersHandler : OverrideImplementMembersHandler(), IntentionAction {
override fun collectMembersToGenerate(descriptor: ClassDescriptor, project: Project): Collection<OverrideMemberChooserObject> { override fun collectMembersToGenerate(descriptor: ClassDescriptor, project: Project): Collection<OverrideMemberChooserObject> {
return OverrideResolver.getMissingImplementations(descriptor) return OverrideResolver.getMissingImplementations(descriptor)
.map { OverrideMemberChooserObject.create(project, it, it) } .map { OverrideMemberChooserObject.create(project, it, it, OverrideMemberChooserObject.BodyType.EMPTY) }
} }
override fun getChooserTitle() = "Implement Members" override fun getChooserTitle() = "Implement Members"
@@ -189,15 +189,15 @@ public abstract class OverrideImplementMembersHandler : LanguageCodeInsightActio
for (selectedElement in selectedElements) { for (selectedElement in selectedElements) {
val descriptor = selectedElement.immediateSuper val descriptor = selectedElement.immediateSuper
when (descriptor) { when (descriptor) {
is SimpleFunctionDescriptor -> overridingMembers.add(overrideFunction(classOrObject, descriptor)) is SimpleFunctionDescriptor -> overridingMembers.add(overrideFunction(classOrObject, descriptor, selectedElement.bodyType))
is PropertyDescriptor -> overridingMembers.add(overrideProperty(classOrObject, descriptor)) is PropertyDescriptor -> overridingMembers.add(overrideProperty(classOrObject, descriptor, selectedElement.bodyType))
else -> error("Unknown member to override: $descriptor") else -> error("Unknown member to override: $descriptor")
} }
} }
return overridingMembers return overridingMembers
} }
private fun overrideProperty(classOrObject: JetClassOrObject, descriptor: PropertyDescriptor): JetElement { private fun overrideProperty(classOrObject: JetClassOrObject, descriptor: PropertyDescriptor, bodyType: OverrideMemberChooserObject.BodyType): JetElement {
val newDescriptor = descriptor.copy(descriptor.containingDeclaration, Modality.OPEN, descriptor.visibility, val newDescriptor = descriptor.copy(descriptor.containingDeclaration, Modality.OPEN, descriptor.visibility,
descriptor.kind, /* copyOverrides = */ true) as PropertyDescriptor descriptor.kind, /* copyOverrides = */ true) as PropertyDescriptor
newDescriptor.addOverriddenDescriptor(descriptor) newDescriptor.addOverriddenDescriptor(descriptor)
@@ -205,7 +205,7 @@ public abstract class OverrideImplementMembersHandler : LanguageCodeInsightActio
val body = StringBuilder { val body = StringBuilder {
append("\nget()") append("\nget()")
append(" = ") append(" = ")
append(generateUnsupportedOrSuperCall(classOrObject, descriptor)) append(generateUnsupportedOrSuperCall(descriptor, bodyType))
if (descriptor.isVar) { if (descriptor.isVar) {
append("\nset(value) {}") append("\nset(value) {}")
} }
@@ -213,31 +213,29 @@ public abstract class OverrideImplementMembersHandler : LanguageCodeInsightActio
return JetPsiFactory(classOrObject.project).createProperty(OVERRIDE_RENDERER.render(newDescriptor) + body) return JetPsiFactory(classOrObject.project).createProperty(OVERRIDE_RENDERER.render(newDescriptor) + body)
} }
private fun overrideFunction(classOrObject: JetClassOrObject, descriptor: FunctionDescriptor): JetNamedFunction { private fun overrideFunction(classOrObject: JetClassOrObject, descriptor: FunctionDescriptor, bodyType: OverrideMemberChooserObject.BodyType): JetNamedFunction {
val newDescriptor = descriptor.copy(descriptor.containingDeclaration, Modality.OPEN, descriptor.visibility, val newDescriptor = descriptor.copy(descriptor.containingDeclaration, Modality.OPEN, descriptor.visibility,
descriptor.kind, /* copyOverrides = */ true) descriptor.kind, /* copyOverrides = */ true)
newDescriptor.addOverriddenDescriptor(descriptor) newDescriptor.addOverriddenDescriptor(descriptor)
val returnType = descriptor.returnType val returnType = descriptor.returnType
val returnsNotUnit = returnType != null && !KotlinBuiltIns.isUnit(returnType) val returnsNotUnit = returnType != null && !KotlinBuiltIns.isUnit(returnType)
val isAbstract = descriptor.modality == Modality.ABSTRACT
val delegation = generateUnsupportedOrSuperCall(classOrObject, descriptor) val delegation = generateUnsupportedOrSuperCall(descriptor, bodyType)
val body = "{" + (if (returnsNotUnit && !isAbstract) "return " else "") + delegation + "}" val body = "{" + (if (returnsNotUnit && bodyType != OverrideMemberChooserObject.BodyType.EMPTY) "return " else "") + delegation + "}"
return JetPsiFactory(classOrObject.project).createFunction(OVERRIDE_RENDERER.render(newDescriptor) + body) return JetPsiFactory(classOrObject.project).createFunction(OVERRIDE_RENDERER.render(newDescriptor) + body)
} }
private fun generateUnsupportedOrSuperCall(classOrObject: JetClassOrObject, descriptor: CallableMemberDescriptor): String { private fun generateUnsupportedOrSuperCall(descriptor: CallableMemberDescriptor, bodyType: OverrideMemberChooserObject.BodyType): String {
val isAbstract = descriptor.modality == Modality.ABSTRACT if (bodyType == OverrideMemberChooserObject.BodyType.EMPTY) {
if (isAbstract) {
return "throw UnsupportedOperationException()" return "throw UnsupportedOperationException()"
} }
else { else {
return StringBuilder { return StringBuilder {
append("super") append("super")
if (classOrObject.getDelegationSpecifiers().size() > 1) { if (bodyType == OverrideMemberChooserObject.BodyType.QUALIFIED_SUPER) {
val superClassFqName = IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(descriptor.containingDeclaration as ClassifierDescriptor) val superClassFqName = IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(descriptor.containingDeclaration as ClassifierDescriptor)
append("<").append(superClassFqName).append(">") append("<").append(superClassFqName).append(">")
} }
@@ -27,24 +27,32 @@ import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.core.util.DescriptorMemberChooserObject import org.jetbrains.kotlin.idea.core.util.DescriptorMemberChooserObject
interface OverrideMemberChooserObject : ClassMember { interface OverrideMemberChooserObject : ClassMember {
enum class BodyType {
EMPTY,
SUPER,
QUALIFIED_SUPER
}
val descriptor: CallableMemberDescriptor val descriptor: CallableMemberDescriptor
val immediateSuper: CallableMemberDescriptor val immediateSuper: CallableMemberDescriptor
val bodyType: BodyType
companion object { companion object {
fun create(project: Project, descriptor: CallableMemberDescriptor, immediateSuper: CallableMemberDescriptor): OverrideMemberChooserObject { fun create(project: Project, descriptor: CallableMemberDescriptor, immediateSuper: CallableMemberDescriptor, bodyType: BodyType): OverrideMemberChooserObject {
val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, descriptor) val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, descriptor)
if (declaration != null) { if (declaration != null) {
return WithDeclaration(descriptor, declaration, immediateSuper) return WithDeclaration(descriptor, declaration, immediateSuper, bodyType)
} }
else { else {
return WithoutDeclaration(descriptor, immediateSuper) return WithoutDeclaration(descriptor, immediateSuper, bodyType)
} }
} }
private class WithDeclaration( private class WithDeclaration(
descriptor: CallableMemberDescriptor, descriptor: CallableMemberDescriptor,
declaration: PsiElement, declaration: PsiElement,
override val immediateSuper: CallableMemberDescriptor override val immediateSuper: CallableMemberDescriptor,
override val bodyType: BodyType
) : DescriptorMemberChooserObject(declaration, descriptor), OverrideMemberChooserObject { ) : DescriptorMemberChooserObject(declaration, descriptor), OverrideMemberChooserObject {
override val descriptor: CallableMemberDescriptor override val descriptor: CallableMemberDescriptor
@@ -53,7 +61,8 @@ interface OverrideMemberChooserObject : ClassMember {
private class WithoutDeclaration( private class WithoutDeclaration(
override val descriptor: CallableMemberDescriptor, override val descriptor: CallableMemberDescriptor,
override val immediateSuper: CallableMemberDescriptor override val immediateSuper: CallableMemberDescriptor,
override val bodyType: BodyType
) : MemberChooserObjectBase(DescriptorMemberChooserObject.getText(descriptor), DescriptorMemberChooserObject.getIcon(null, descriptor)), OverrideMemberChooserObject { ) : MemberChooserObjectBase(DescriptorMemberChooserObject.getText(descriptor), DescriptorMemberChooserObject.getIcon(null, descriptor)), OverrideMemberChooserObject {
override fun getParentNodeDelegate(): MemberChooserObject? { override fun getParentNodeDelegate(): MemberChooserObject? {
@@ -18,8 +18,7 @@ package org.jetbrains.kotlin.idea.core.overrideImplement
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import java.util.ArrayList import java.util.*
import java.util.LinkedHashMap
public class OverrideMembersHandler : OverrideImplementMembersHandler() { public class OverrideMembersHandler : OverrideImplementMembersHandler() {
override fun collectMembersToGenerate(descriptor: ClassDescriptor, project: Project): Collection<OverrideMemberChooserObject> { override fun collectMembersToGenerate(descriptor: ClassDescriptor, project: Project): Collection<OverrideMemberChooserObject> {
@@ -56,7 +55,15 @@ public class OverrideMembersHandler : OverrideImplementMembersHandler() {
else { else {
immediateSupers.singleOrNull { (it.containingDeclaration as? ClassDescriptor)?.kind == ClassKind.CLASS } ?: immediateSupers.first() immediateSupers.singleOrNull { (it.containingDeclaration as? ClassDescriptor)?.kind == ClassKind.CLASS } ?: immediateSupers.first()
} }
result.add(OverrideMemberChooserObject.create(project, realSuper, immediateSuperToUse))
val bodyType = if (immediateSuperToUse.modality == Modality.ABSTRACT)
OverrideMemberChooserObject.BodyType.EMPTY
else if (realSupersToUse.size() == 1)
OverrideMemberChooserObject.BodyType.SUPER
else
OverrideMemberChooserObject.BodyType.QUALIFIED_SUPER
result.add(OverrideMemberChooserObject.create(project, realSuper, immediateSuperToUse, bodyType))
} }
} }
} }
@@ -1,3 +1,5 @@
// ERROR: 'internal open fun foo(): kotlin.Unit' is already defined in C
// ERROR: 'internal open fun foo(): kotlin.Unit' is already defined in C
interface I { interface I {
open fun foo(){} open fun foo(){}
} }
@@ -8,7 +10,7 @@ open class A {
class C : A(), I { class C : A(), I {
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
<selection><caret>return super<A>.equals(other)</selection> <selection><caret>return super.equals(other)</selection>
} }
override fun foo() { override fun foo() {
@@ -20,10 +22,10 @@ class C : A(), I {
} }
override fun hashCode(): Int { override fun hashCode(): Int {
return super<A>.hashCode() return super.hashCode()
} }
override fun toString(): String { override fun toString(): String {
return super<A>.toString() return super.toString()
} }
} }
@@ -15,11 +15,11 @@ abstract class B : A() {
class C : B(), I { class C : B(), I {
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
<selection><caret>return super<B>.equals(other)</selection> <selection><caret>return super.equals(other)</selection>
} }
override fun f() { override fun f() {
super<B>.f() super.f()
} }
override fun g() { override fun g() {
@@ -27,10 +27,10 @@ class C : B(), I {
} }
override fun hashCode(): Int { override fun hashCode(): Int {
return super<B>.hashCode() return super.hashCode()
} }
override fun toString(): String { override fun toString(): String {
return super<B>.toString() return super.toString()
} }
} }
@@ -2,6 +2,6 @@ open class A {
open fun foo(`object` : Any): Int = 0 open fun foo(`object` : Any): Int = 0
} }
class C : A { class C : A() {
<caret> <caret>
} }
@@ -2,7 +2,7 @@ open class A {
open fun foo(`object` : Any): Int = 0 open fun foo(`object` : Any): Int = 0
} }
class C : A { class C : A() {
override fun foo(`object`: Any): Int { override fun foo(`object`: Any): Int {
<selection><caret>return super.foo(`object`)</selection> <selection><caret>return super.foo(`object`)</selection>
} }
@@ -1,5 +1,6 @@
// see KT-8942
interface Trait { interface Trait {
fun <A, B : Runnable, E : Map.Entry<A, B>> foo() where B : Cloneable, B : Comparable<B>; fun <A, B : Runnable, E : Map.Entry<A, B>> foo() where B : Cloneable, B : Comparable<B>
} }
class TraitImpl : Trait { class TraitImpl : Trait {
@@ -1,5 +1,8 @@
// ERROR: 'foo' overrides nothing
// ERROR: Class 'TraitImpl' must be declared abstract or implement abstract member internal abstract fun <A, B : java.lang.Runnable, E : kotlin.Map.Entry<A, B>> foo(): kotlin.Unit where B : kotlin.Cloneable, B : kotlin.Comparable<B> defined in Trait
// see KT-8942
interface Trait { interface Trait {
fun <A, B : Runnable, E : Map.Entry<A, B>> foo() where B : Cloneable, B : Comparable<B>; fun <A, B : Runnable, E : Map.Entry<A, B>> foo() where B : Cloneable, B : Comparable<B>
} }
class TraitImpl : Trait { class TraitImpl : Trait {
@@ -1,3 +1,3 @@
class X : java.util.ArrayList<String>(), Runnable { abstract class X : java.util.ArrayList<String>(), Runnable {
<caret> <caret>
} }
@@ -1,7 +1,5 @@
import java.util.ArrayList abstract class X : java.util.ArrayList<String>(), Runnable {
class X : java.util.ArrayList<String>(), Runnable {
override fun size(): Int { override fun size(): Int {
<selection><caret>return super<ArrayList>.size()</selection> <selection><caret>return super.size()</selection>
} }
} }
@@ -12,35 +12,35 @@ interface B {
class C : A(), B { class C : A(), B {
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
<selection><caret>return super<A>.equals(other)</selection> <selection><caret>return super.equals(other)</selection>
} }
override fun hashCode(): Int { override fun hashCode(): Int {
return super<A>.hashCode() return super.hashCode()
} }
override fun internalFun() { override fun internalFun() {
super<A>.internalFun() super.internalFun()
} }
override val internalProperty: Int override val internalProperty: Int
get() = throw UnsupportedOperationException() get() = throw UnsupportedOperationException()
override fun protectedFun() { override fun protectedFun() {
super<A>.protectedFun() super.protectedFun()
} }
override val protectedProperty: Int override val protectedProperty: Int
get() = throw UnsupportedOperationException() get() = throw UnsupportedOperationException()
override fun publicFun() { override fun publicFun() {
super<A>.publicFun() super.publicFun()
} }
override val publicProperty: Int override val publicProperty: Int
get() = throw UnsupportedOperationException() get() = throw UnsupportedOperationException()
override fun toString(): String { override fun toString(): String {
return super<A>.toString() return super.toString()
} }
} }
+1 -1
View File
@@ -5,7 +5,7 @@ abstract class C<A> {
fun f() { fun f() {
class R class R
object : C<R> { object : C<R>() {
<caret> <caret>
} }
} }
@@ -5,7 +5,7 @@ abstract class C<A> {
fun f() { fun f() {
class R class R
object : C<R> { object : C<R>() {
override fun f(a: R) { override fun f(a: R) {
<selection><caret>throw UnsupportedOperationException()</selection> <selection><caret>throw UnsupportedOperationException()</selection>
} }
@@ -12,18 +12,18 @@ class C : A(), B {
} }
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
return super<A>.equals(other) return super.equals(other)
} }
override fun foo() { override fun foo() {
super<A>.foo() super.foo()
} }
override fun hashCode(): Int { override fun hashCode(): Int {
return super<A>.hashCode() return super.hashCode()
} }
override fun toString(): String { override fun toString(): String {
return super<A>.toString() return super.toString()
} }
} }
@@ -1,3 +1,4 @@
// ERROR: Unresolved reference: println
open class A() { open class A() {
open val method : () -> Unit? = {println("hello")} open val method : () -> Unit? = {println("hello")}
} }
@@ -1,3 +1,4 @@
// ERROR: Unresolved reference: println
interface A<T> { interface A<T> {
fun foo(value : T) : Unit = println(value) fun foo(value : T) : Unit = println(value)
} }
@@ -1,6 +1,6 @@
package foo; package foo;
class A { public class A {
public int getAnswer(String[] array, int number, Object value) { public int getAnswer(String[] array, int number, Object value) {
return 42; return 42;
} }
@@ -1,3 +1,4 @@
// ERROR: Unresolved reference: println
open class A() { open class A() {
open fun foo(value : Int) : Unit = println(value) open fun foo(value : Int) : Unit = println(value)
open val bar : Int = 0 open val bar : Int = 0
@@ -1,5 +1,5 @@
interface A { interface A {
fun foo(value : String) : Unit = 0 fun foo(value : String) : Unit {}
} }
class C : A { class C : A {
@@ -1,5 +1,5 @@
interface A { interface A {
fun foo(value : String) : Unit = 0 fun foo(value : String) : Unit {}
} }
class C : A { class C : A {
@@ -4,19 +4,19 @@ interface I {
class C : A(), I { class C : A(), I {
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
<selection><caret>return super<A>.equals(other)</selection> <selection><caret>return super.equals(other)</selection>
} }
override fun hashCode(): Int { override fun hashCode(): Int {
return super<A>.hashCode() return super.hashCode()
} }
override fun toString(): String { override fun toString(): String {
return super<A>.toString() return super.toString()
} }
override fun x() { override fun x() {
super<A>.x() super.x()
} }
override fun z() { override fun z() {
@@ -10,6 +10,6 @@ class Outer {
class X : Outer.Inner1, Outer.Inner2 { class X : Outer.Inner1, Outer.Inner2 {
override fun f() { override fun f() {
<selection><caret>super<Outer.Inner1>.f()</selection> <selection><caret>super.f()</selection>
} }
} }
@@ -5,4 +5,4 @@ public class Impl : ArrayFactory {
<caret> <caret>
} }
val array: Array<String> val array: Array<String> = emptyArray()
@@ -1,3 +1,4 @@
// ERROR: Unresolved reference: emptyArray
//KT-1602 //KT-1602
import lib.ArrayFactory import lib.ArrayFactory
@@ -7,4 +8,4 @@ public class Impl : ArrayFactory {
} }
} }
val array: Array<String> val array: Array<String> = emptyArray()
@@ -18,15 +18,15 @@ interface I3 {
abstract class B : I2, A(), I3 { abstract class B : I2, A(), I3 {
override fun a() { override fun a() {
<selection><caret>super<A>.a()</selection> <selection><caret>super.a()</selection>
} }
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
return super<A>.equals(other) return super.equals(other)
} }
override fun hashCode(): Int { override fun hashCode(): Int {
return super<A>.hashCode() return super.hashCode()
} }
override fun i() { override fun i() {
@@ -42,6 +42,6 @@ abstract class B : I2, A(), I3 {
} }
override fun toString(): String { override fun toString(): String {
return super<A>.toString() return super.toString()
} }
} }
@@ -34,8 +34,10 @@ import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMemberChooserObj
import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMembersHandler import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMembersHandler
import org.jetbrains.kotlin.idea.test.JetLightCodeInsightFixtureTestCase import org.jetbrains.kotlin.idea.test.JetLightCodeInsightFixtureTestCase
import org.jetbrains.kotlin.idea.test.JetLightProjectDescriptor import org.jetbrains.kotlin.idea.test.JetLightProjectDescriptor
import org.jetbrains.kotlin.idea.test.dumpTextWithErrors
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.psi.JetClassOrObject import org.jetbrains.kotlin.psi.JetClassOrObject
import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.test.JetTestUtils import org.jetbrains.kotlin.test.JetTestUtils
import org.jetbrains.kotlin.test.TagsTestDataUtil import org.jetbrains.kotlin.test.TagsTestDataUtil
import org.jetbrains.kotlin.utils.rethrow import org.jetbrains.kotlin.utils.rethrow
@@ -187,6 +189,11 @@ public abstract class AbstractOverrideImplementTest : JetLightCodeInsightFixture
val expectedFile = File(myFixture.testDataPath, fileName) val expectedFile = File(myFixture.testDataPath, fileName)
try { try {
Assert.assertTrue(expectedFile.exists()) Assert.assertTrue(expectedFile.exists())
val file = myFixture.file as JetFile
val document = myFixture.getDocument(file)
myFixture.project.executeWriteCommand("") {
document.replaceString(0, document.textLength, file.dumpTextWithErrors())
}
myFixture.checkResultByFile(fileName) myFixture.checkResultByFile(fileName)
} }
catch (error: AssertionError) { catch (error: AssertionError) {