diff --git a/.idea/dictionaries/valentin.xml b/.idea/dictionaries/valentin.xml
index f97358c1c99..5cebee5ec8d 100644
--- a/.idea/dictionaries/valentin.xml
+++ b/.idea/dictionaries/valentin.xml
@@ -5,6 +5,7 @@
decapitalize
delegator
funs
+ immediates
initializers
inserter
negatable
diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/DescriptorClassMember.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/DescriptorClassMember.kt
index 1890e13fd6f..4a3dfec3833 100644
--- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/DescriptorClassMember.kt
+++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/DescriptorClassMember.kt
@@ -18,16 +18,18 @@ package org.jetbrains.kotlin.idea.core.overrideImplement
import com.intellij.codeInsight.generation.ClassMemberWithElement
import com.intellij.codeInsight.generation.MemberChooserObject
-import com.intellij.codeInsight.generation.MemberChooserObjectBase
import com.intellij.codeInsight.generation.PsiElementMemberChooserObject
+import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Iconable
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMember
import com.intellij.psi.util.PsiTreeUtil
+import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.idea.JetDescriptorIconProvider
+import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.psi.JetClass
import org.jetbrains.kotlin.psi.JetDeclaration
import org.jetbrains.kotlin.psi.JetFile
@@ -39,10 +41,16 @@ import org.jetbrains.kotlin.renderer.render
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import javax.swing.Icon
-public class DescriptorClassMember(
- private val psiElement: PsiElement,
+class OverrideMemberChooserObject(
+ project: Project,
+ val member: CallableMemberDescriptor,
+ val immediateSuper: CallableMemberDescriptor
+) : DescriptorClassMember(DescriptorToSourceUtilsIde.getAnyDeclaration(project, member)!!, member)
+
+public open class DescriptorClassMember(
+ psiElement: PsiElement,
public val descriptor: DeclarationDescriptor
-) : MemberChooserObjectBase(DescriptorClassMember.getText(descriptor), DescriptorClassMember.getIcon(psiElement, descriptor)), ClassMemberWithElement {
+) : PsiElementMemberChooserObject(psiElement, DescriptorClassMember.getText(descriptor), DescriptorClassMember.getIcon(psiElement, descriptor)), ClassMemberWithElement {
override fun getParentNodeDelegate(): MemberChooserObject {
val parent = descriptor.containingDeclaration ?: error("No parent for $descriptor")
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 a368f1e6d29..e6772fe81f3 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
@@ -25,7 +25,10 @@ import org.jetbrains.kotlin.idea.JetBundle
import org.jetbrains.kotlin.resolve.OverrideResolver
public class ImplementMethodsHandler : OverrideImplementMethodsHandler(), IntentionAction {
- override fun collectMethodsToGenerate(descriptor: ClassDescriptor) = OverrideResolver.getMissingImplementations(descriptor)
+ override fun collectMethodsToGenerate(descriptor: ClassDescriptor, project: Project): Collection {
+ return OverrideResolver.getMissingImplementations(descriptor)
+ .map { OverrideMemberChooserObject(project, it, it) }
+ }
override fun getChooserTitle() = "Implement Members"
diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/OverrideImplementMethodsHandler.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/OverrideImplementMethodsHandler.kt
index 6a4cf8040c7..29d1959cd12 100644
--- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/OverrideImplementMethodsHandler.kt
+++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/overrideImplement/OverrideImplementMethodsHandler.kt
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.idea.core.overrideImplement
import com.intellij.codeInsight.hint.HintManager
import com.intellij.ide.util.MemberChooser
import com.intellij.lang.LanguageCodeInsightActionHandler
-import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.DialogWrapper
@@ -29,7 +28,6 @@ import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
-import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.quickfix.moveCaretIntoGeneratedElement
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.util.ShortenReferences
@@ -41,14 +39,14 @@ import java.util.ArrayList
public abstract class OverrideImplementMethodsHandler : LanguageCodeInsightActionHandler {
- public fun collectMethodsToGenerate(classOrObject: JetClassOrObject): Set {
+ public fun collectMethodsToGenerate(classOrObject: JetClassOrObject): Collection {
val descriptor = classOrObject.resolveToDescriptor() as? ClassDescriptor ?: return emptySet()
- return collectMethodsToGenerate(descriptor)
+ return collectMethodsToGenerate(descriptor, classOrObject.project)
}
- protected abstract fun collectMethodsToGenerate(descriptor: ClassDescriptor): Set
+ protected abstract fun collectMethodsToGenerate(descriptor: ClassDescriptor, project: Project): Collection
- private fun showOverrideImplementChooser(project: Project, members: Array): MemberChooser? {
+ private fun showOverrideImplementChooser(project: Project, members: Array): MemberChooser? {
val chooser = MemberChooser(members, true, true, project)
chooser.title = getChooserTitle()
chooser.show()
@@ -71,15 +69,13 @@ public abstract class OverrideImplementMethodsHandler : LanguageCodeInsightActio
val elementAtCaret = file.findElementAt(editor.caretModel.offset)
val classOrObject = elementAtCaret?.getNonStrictParentOfType()!!
- val missingImplementations = collectMethodsToGenerate(classOrObject)
- if (missingImplementations.isEmpty() && !implementAll) {
+ val members = collectMethodsToGenerate(classOrObject)
+ if (members.isEmpty() && !implementAll) {
HintManager.getInstance().showErrorHint(editor, getNoMethodsFoundHint())
return
}
- val members = membersFromDescriptors(file as JetFile, missingImplementations)
-
- val selectedElements: List = if (implementAll) {
+ val selectedElements = if (implementAll) {
members
}
else {
@@ -108,23 +104,7 @@ public abstract class OverrideImplementMethodsHandler : LanguageCodeInsightActio
typeNormalizer = IdeDescriptorRenderers.APPROXIMATE_FLEXIBLE_TYPES
}
- private val LOG = Logger.getInstance(javaClass().canonicalName)
-
- public fun membersFromDescriptors(file: JetFile, missingImplementations: Iterable): List {
- val members = ArrayList()
- for (memberDescriptor in missingImplementations) {
- val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(file.project, memberDescriptor)
- if (declaration == null) {
- LOG.error("Can not find declaration for descriptor $memberDescriptor")
- }
- else {
- members.add(DescriptorClassMember(declaration, memberDescriptor))
- }
- }
- return members
- }
-
- public fun generateMethods(editor: Editor, classOrObject: JetClassOrObject, selectedElements: List) {
+ public fun generateMethods(editor: Editor, classOrObject: JetClassOrObject, selectedElements: Collection) {
runWriteAction {
val body = classOrObject.getOrCreateBody()
@@ -203,16 +183,15 @@ public abstract class OverrideImplementMethodsHandler : LanguageCodeInsightActio
return whiteSpace
}
- private fun generateOverridingMembers(selectedElements: List,
+ private fun generateOverridingMembers(selectedElements: Collection,
classOrObject: JetClassOrObject): List {
val overridingMembers = ArrayList()
for (selectedElement in selectedElements) {
- val descriptor = selectedElement.descriptor
- if (descriptor is SimpleFunctionDescriptor) {
- overridingMembers.add(overrideFunction(classOrObject, descriptor))
- }
- else if (descriptor is PropertyDescriptor) {
- overridingMembers.add(overrideProperty(classOrObject, descriptor))
+ val descriptor = selectedElement.immediateSuper
+ when (descriptor) {
+ is SimpleFunctionDescriptor -> overridingMembers.add(overrideFunction(classOrObject, descriptor))
+ is PropertyDescriptor -> overridingMembers.add(overrideProperty(classOrObject, descriptor))
+ else -> error("Unknown member to override: $descriptor")
}
}
return overridingMembers
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 cef375214e7..9658f1d4e36 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
@@ -16,53 +16,61 @@
package org.jetbrains.kotlin.idea.core.overrideImplement
-import com.google.common.collect.LinkedHashMultimap
+import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
-import org.jetbrains.kotlin.resolve.OverrideResolver
-import org.jetbrains.kotlin.resolve.OverridingUtil
-import org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE
-import org.jetbrains.kotlin.resolve.calls.callResolverUtil.isOrOverridesSynthesized
+import org.jetbrains.kotlin.descriptors.ClassKind
+import org.jetbrains.kotlin.descriptors.Modality
+import java.util.ArrayList
+import java.util.LinkedHashMap
public class OverrideMethodsHandler : OverrideImplementMethodsHandler() {
- override fun collectMethodsToGenerate(descriptor: ClassDescriptor): Set {
- val superMethods = collectSuperMethods(descriptor)
- for (member in descriptor.defaultType.memberScope.getAllDescriptors()) {
- if (member is CallableMemberDescriptor) {
- if (member.kind == CallableMemberDescriptor.Kind.DECLARATION) {
- superMethods.removeAll(member.overriddenDescriptors)
+ override fun collectMethodsToGenerate(descriptor: ClassDescriptor, project: Project): Collection {
+ val result = ArrayList()
+ for (member in descriptor.unsubstitutedMemberScope.getAllDescriptors()) {
+ if (member is CallableMemberDescriptor && !member.isReal()) {
+ val overridden = member.overriddenDescriptors
+ if (overridden.any { it.modality == Modality.FINAL }) continue
+
+ val realSuperToImmediates = LinkedHashMap>()
+ for (immediateSuper in overridden) {
+ for (realSuper in toRealSupers(immediateSuper)) {
+ realSuperToImmediates.getOrPut(realSuper) { ArrayList(1) }.add(immediateSuper)
+ }
+ }
+
+ val realSupers = realSuperToImmediates.keySet()
+ val nonAbstractRealSupers = realSupers.filter { it.modality != Modality.ABSTRACT }
+ val realSupersToUse = if (nonAbstractRealSupers.isNotEmpty()) {
+ nonAbstractRealSupers
+ }
+ else {
+ listOf(realSupers.first())
+ }
+
+ for (realSuper in realSupersToUse) {
+ val immediateSupers = realSuperToImmediates[realSuper]!!
+ assert(immediateSupers.isNotEmpty())
+
+ val immediateSuperToUse = if (immediateSupers.size() == 1) {
+ immediateSupers.single()
+ }
+ else {
+ immediateSupers.singleOrNull { (it.containingDeclaration as? ClassDescriptor)?.kind == ClassKind.CLASS } ?: immediateSupers.first()
+ }
+ result.add(OverrideMemberChooserObject(project, realSuper, immediateSuperToUse))
}
}
}
-
- return superMethods
- .filter { it.modality.isOverridable && !isOrOverridesSynthesized(it) }
- .toSet()
+ return result
}
- private fun collectSuperMethods(classDescriptor: ClassDescriptor): MutableSet {
- val inheritedFunctionsSet = classDescriptor.typeConstructor.supertypes
- .flatMap { it.memberScope.getAllDescriptors() }
- .filterIsInstance()
- .toSet()
+ private fun CallableMemberDescriptor.isReal() = kind == CallableMemberDescriptor.Kind.DECLARATION
- // Only those actually inherited
- val filteredMembers = OverrideResolver.filterOutOverridden(inheritedFunctionsSet)
-
- // Group members with "the same" signature
- val factoredMembers = LinkedHashMultimap.create()
- for (one in filteredMembers) {
- if (factoredMembers.values().contains(one)) continue
- for (another in filteredMembers) {
- // if (one == another) continue;
- factoredMembers.put(one, one)
- if (OverridingUtil.DEFAULT.isOverridableBy(one, another).result == OVERRIDABLE || OverridingUtil.DEFAULT.isOverridableBy(another, one).result == OVERRIDABLE) {
- factoredMembers.put(one, another)
- }
- }
- }
-
- return factoredMembers.keySet()
+ private fun toRealSupers(immediateSuper: CallableMemberDescriptor): Collection {
+ val overridden = immediateSuper.overriddenDescriptors
+ if (overridden.isEmpty()) return listOf(immediateSuper)
+ return overridden.flatMap { toRealSupers(it) }.toSet()
}
override fun getChooserTitle() = "Override Members"
diff --git a/idea/testData/codeInsight/overrideImplement/ambiguousSuper.kt b/idea/testData/codeInsight/overrideImplement/ambiguousSuper.kt
new file mode 100644
index 00000000000..103a4525396
--- /dev/null
+++ b/idea/testData/codeInsight/overrideImplement/ambiguousSuper.kt
@@ -0,0 +1,11 @@
+interface I {
+ open fun foo(){}
+}
+
+open class A {
+ open fun foo(){}
+}
+
+class C : A(), I {
+
+}
\ No newline at end of file
diff --git a/idea/testData/codeInsight/overrideImplement/ambiguousSuper.kt.after b/idea/testData/codeInsight/overrideImplement/ambiguousSuper.kt.after
new file mode 100644
index 00000000000..a6c470bc28c
--- /dev/null
+++ b/idea/testData/codeInsight/overrideImplement/ambiguousSuper.kt.after
@@ -0,0 +1,29 @@
+interface I {
+ open fun foo(){}
+}
+
+open class A {
+ open fun foo(){}
+}
+
+class C : A(), I {
+ override fun equals(other: Any?): Boolean {
+ return super.equals(other)
+ }
+
+ override fun foo() {
+ super.foo()
+ }
+
+ override fun foo() {
+ super.foo()
+ }
+
+ override fun hashCode(): Int {
+ return super.hashCode()
+ }
+
+ override fun toString(): String {
+ return super.toString()
+ }
+}
\ No newline at end of file
diff --git a/idea/testData/codeInsight/overrideImplement/doNotOverrideFinal.kt b/idea/testData/codeInsight/overrideImplement/doNotOverrideFinal.kt
new file mode 100644
index 00000000000..9d121663483
--- /dev/null
+++ b/idea/testData/codeInsight/overrideImplement/doNotOverrideFinal.kt
@@ -0,0 +1,18 @@
+open class A {
+ fun a(){}
+ fun b(){}
+}
+
+interface I {
+ fun b()
+}
+
+abstract class B : A() {
+ open fun f(){}
+ abstract fun g()
+ fun h(){}
+}
+
+class C : B(), I {
+
+}
diff --git a/idea/testData/codeInsight/overrideImplement/doNotOverrideFinal.kt.after b/idea/testData/codeInsight/overrideImplement/doNotOverrideFinal.kt.after
new file mode 100644
index 00000000000..cb95729e021
--- /dev/null
+++ b/idea/testData/codeInsight/overrideImplement/doNotOverrideFinal.kt.after
@@ -0,0 +1,36 @@
+open class A {
+ fun a(){}
+ fun b(){}
+}
+
+interface I {
+ fun b()
+}
+
+abstract class B : A() {
+ open fun f(){}
+ abstract fun g()
+ fun h(){}
+}
+
+class C : B(), I {
+ override fun equals(other: Any?): Boolean {
+ return super.equals(other)
+ }
+
+ override fun f() {
+ super.f()
+ }
+
+ override fun g() {
+ throw UnsupportedOperationException()
+ }
+
+ override fun hashCode(): Int {
+ return super.hashCode()
+ }
+
+ override fun toString(): String {
+ return super.toString()
+ }
+}
diff --git a/idea/testData/codeInsight/overrideImplement/superPreference.kt b/idea/testData/codeInsight/overrideImplement/superPreference.kt
new file mode 100644
index 00000000000..0828885210b
--- /dev/null
+++ b/idea/testData/codeInsight/overrideImplement/superPreference.kt
@@ -0,0 +1,21 @@
+abstract class A : I1 {
+ open fun a(){}
+}
+
+interface I1 {
+ fun i1()
+ fun i()
+}
+
+interface I2 {
+ fun i2()
+ fun a()
+}
+
+interface I3 {
+ fun i()
+}
+
+abstract class B : I2, A(), I3 {
+
+}
diff --git a/idea/testData/codeInsight/overrideImplement/superPreference.kt.after b/idea/testData/codeInsight/overrideImplement/superPreference.kt.after
new file mode 100644
index 00000000000..c2dcad42755
--- /dev/null
+++ b/idea/testData/codeInsight/overrideImplement/superPreference.kt.after
@@ -0,0 +1,47 @@
+abstract class A : I1 {
+ open fun a(){}
+}
+
+interface I1 {
+ fun i1()
+ fun i()
+}
+
+interface I2 {
+ fun i2()
+ fun a()
+}
+
+interface I3 {
+ fun i()
+}
+
+abstract class B : I2, A(), I3 {
+ override fun a() {
+ super.a()
+ }
+
+ override fun equals(other: Any?): Boolean {
+ return super.equals(other)
+ }
+
+ override fun hashCode(): Int {
+ return super.hashCode()
+ }
+
+ override fun i() {
+ throw UnsupportedOperationException()
+ }
+
+ override fun i1() {
+ throw UnsupportedOperationException()
+ }
+
+ override fun i2() {
+ throw UnsupportedOperationException()
+ }
+
+ override fun toString(): String {
+ return super.toString()
+ }
+}
diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractOverrideImplementTest.java b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractOverrideImplementTest.java
deleted file mode 100644
index 97fc3a178d3..00000000000
--- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractOverrideImplementTest.java
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * 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.codeInsight;
-
-import com.intellij.codeInsight.generation.OverrideImplementUtil;
-import com.intellij.codeInsight.generation.PsiMethodMember;
-import com.intellij.openapi.application.Result;
-import com.intellij.openapi.command.WriteCommandAction;
-import com.intellij.openapi.project.Project;
-import com.intellij.psi.*;
-import com.intellij.psi.impl.source.PostprocessReformattingAspect;
-import com.intellij.psi.search.GlobalSearchScope;
-import com.intellij.psi.util.PsiTreeUtil;
-import com.intellij.testFramework.LightProjectDescriptor;
-import com.intellij.util.SmartList;
-import kotlin.KotlinPackage;
-import kotlin.jvm.functions.Function1;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
-import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor;
-import org.jetbrains.kotlin.descriptors.ClassDescriptor;
-import org.jetbrains.kotlin.idea.core.overrideImplement.DescriptorClassMember;
-import org.jetbrains.kotlin.idea.core.overrideImplement.ImplementMethodsHandler;
-import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideImplementMethodsHandler;
-import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMethodsHandler;
-import org.jetbrains.kotlin.idea.test.JetLightCodeInsightFixtureTestCase;
-import org.jetbrains.kotlin.idea.test.JetLightProjectDescriptor;
-import org.jetbrains.kotlin.psi.JetClassOrObject;
-import org.jetbrains.kotlin.psi.JetFile;
-import org.jetbrains.kotlin.resolve.OverrideResolver;
-import org.jetbrains.kotlin.test.JetTestUtils;
-import org.jetbrains.kotlin.test.TagsTestDataUtil;
-import org.jetbrains.kotlin.utils.UtilsPackage;
-import org.junit.Assert;
-
-import java.io.File;
-import java.util.*;
-
-public abstract class AbstractOverrideImplementTest extends JetLightCodeInsightFixtureTestCase {
- @NotNull
- @Override
- protected LightProjectDescriptor getProjectDescriptor() {
- return JetLightProjectDescriptor.INSTANCE;
- }
-
- protected void doImplementFileTest() {
- doFileTest(new ImplementMethodsHandler());
- }
-
- protected void doOverrideFileTest() {
- doFileTest(new OverrideMethodsHandler());
- }
-
- protected void doMultiImplementFileTest() {
- doMultiFileTest(new ImplementMethodsHandler());
- }
-
- protected void doMultiOverrideFileTest() {
- doMultiFileTest(new OverrideMethodsHandler());
- }
-
- protected void doImplementDirectoryTest() {
- doDirectoryTest(new ImplementMethodsHandler());
- }
-
- protected void doOverrideDirectoryTest(@Nullable String memberToImplement) {
- doDirectoryTest(new OverrideMethodsHandler(), memberToImplement);
- }
-
- protected void doImplementJavaDirectoryTest(String className, String methodName) {
- myFixture.copyDirectoryToProject(getTestName(true), "");
- myFixture.configureFromTempProjectFile("foo/JavaClass.java");
-
- Project project = myFixture.getProject();
-
- PsiClass aClass = JavaPsiFacade.getInstance(project).findClass(className, GlobalSearchScope.allScope(project));
- Assert.assertNotNull("Can't find class: " + className, aClass);
-
- PsiMethod method = aClass.findMethodsByName(methodName, false)[0];
- Assert.assertNotNull(String.format("Can't find method '%s' in class %s", methodName, className), method);
-
- generateImplementation(method);
-
- myFixture.checkResultByFile(getTestName(true) + "/foo/JavaClass.java.after");
- }
-
- private void doFileTest(OverrideImplementMethodsHandler handler) {
- myFixture.configureByFile(getTestName(true) + ".kt");
- doOverrideImplement(handler, null);
- checkResultByFile(getTestName(true) + ".kt.after");
- }
-
- private void doMultiFileTest(OverrideImplementMethodsHandler handler) {
- myFixture.configureByFile(getTestName(true) + ".kt");
- doMultiOverrideImplement(handler);
- checkResultByFile(getTestName(true) + ".kt.after");
- }
-
- protected void doDirectoryTest(OverrideImplementMethodsHandler handler) {
- doDirectoryTest(handler, null);
- }
-
- private void doDirectoryTest(OverrideImplementMethodsHandler handler, @Nullable String memberToOverride) {
- myFixture.copyDirectoryToProject(getTestName(true), "");
- myFixture.configureFromTempProjectFile("foo/Impl.kt");
- doOverrideImplement(handler, memberToOverride);
- checkResultByFile(getTestName(true) + "/foo/Impl.kt.after");
- }
-
- private void doOverrideImplement(OverrideImplementMethodsHandler handler, @Nullable String memberToOverride) {
- PsiElement elementAtCaret = myFixture.getFile().findElementAt(myFixture.getEditor().getCaretModel().getOffset());
- JetClassOrObject classOrObject = PsiTreeUtil.getParentOfType(elementAtCaret, JetClassOrObject.class);
- assertNotNull("Caret should be inside class or object", classOrObject);
-
- JetFile jetFile = classOrObject.getContainingJetFile();
- Set descriptors = handler.collectMethodsToGenerate(classOrObject);
-
- CallableMemberDescriptor singleToOverride;
- if (memberToOverride == null) {
- // Filter out fake overrides of members of Any (equals, hashCode, toString)
- List filtered = KotlinPackage.filter(descriptors, new Function1() {
- @Override
- public Boolean invoke(CallableMemberDescriptor descriptor) {
- ClassDescriptor any = KotlinBuiltIns.getInstance().getAny();
- for (CallableMemberDescriptor overridden : OverrideResolver.getOverriddenDeclarations(descriptor)) {
- if (overridden.getContainingDeclaration().equals(any)) {
- return false;
- }
- }
- return true;
- }
- });
- assertEquals("Invalid number of available descriptors for override", 1, filtered.size());
- singleToOverride = filtered.iterator().next();
- }
- else {
- CallableMemberDescriptor candidateToOverride = null;
- for (CallableMemberDescriptor callable : descriptors) {
- if (callable.getName().asString().equals(memberToOverride)) {
- if (candidateToOverride != null) {
- throw new IllegalStateException("more then one descriptor with name " + memberToOverride);
- }
- candidateToOverride = callable;
- }
- }
- if (candidateToOverride == null) {
- throw new IllegalStateException("no descriptors to override with name " + memberToOverride + " found");
- }
- singleToOverride = candidateToOverride;
- }
-
- performGenerateCommand(classOrObject,
- OverrideImplementMethodsHandler.Companion.membersFromDescriptors(jetFile, Collections.singletonList(singleToOverride)));
- }
-
- private void doMultiOverrideImplement(OverrideImplementMethodsHandler handler) {
- PsiElement elementAtCaret = myFixture.getFile().findElementAt(myFixture.getEditor().getCaretModel().getOffset());
- JetClassOrObject classOrObject = PsiTreeUtil.getParentOfType(elementAtCaret, JetClassOrObject.class);
- assertNotNull("Caret should be inside class or object", classOrObject);
-
- JetFile jetFile = classOrObject.getContainingJetFile();
- Set descriptors = handler.collectMethodsToGenerate(classOrObject);
-
- List descriptorsList = new ArrayList(descriptors);
- Collections.sort(descriptorsList, new Comparator() {
- @Override
- public int compare(@NotNull CallableMemberDescriptor desc1, @NotNull CallableMemberDescriptor desc2) {
- return desc1.getName().compareTo(desc2.getName());
- }
- });
-
- performGenerateCommand(classOrObject, OverrideImplementMethodsHandler.Companion.membersFromDescriptors(jetFile, descriptorsList));
- }
-
- private void generateImplementation(@NotNull final PsiMethod method) {
- WriteCommandAction.runWriteCommandAction(getProject(), new Runnable() {
- @Override
- public void run() {
- PsiClass aClass = ((PsiClassOwner) myFixture.getFile()).getClasses()[0];
-
- PsiMethodMember methodMember = new PsiMethodMember(method, PsiSubstitutor.EMPTY);
-
- OverrideImplementUtil.overrideOrImplementMethodsInRightPlace(
- myFixture.getEditor(), aClass, new SmartList(methodMember), false);
-
- PostprocessReformattingAspect.getInstance(myFixture.getProject()).doPostponedFormatting();
- }
- });
- }
-
- private void performGenerateCommand(
- final JetClassOrObject classOrObject,
- final List descriptorsToGenerate
- ) {
- try {
- new WriteCommandAction(myFixture.getProject(), myFixture.getFile()) {
- @Override
- protected void run(@NotNull Result result) throws Throwable {
- OverrideImplementMethodsHandler.Companion.generateMethods(myFixture.getEditor(), classOrObject, descriptorsToGenerate);
- }
- }.performCommand();
- }
- catch (Throwable throwable) {
- throw UtilsPackage.rethrow(throwable);
- }
- }
-
- private void checkResultByFile(String fileName) {
- File expectedFile = new File(myFixture.getTestDataPath(), fileName);
- try {
- Assert.assertTrue(expectedFile.exists());
- myFixture.checkResultByFile(fileName);
- }
- catch (AssertionError error) {
- JetTestUtils.assertEqualsToFile(expectedFile, TagsTestDataUtil.generateTextWithCaretAndSelection(myFixture.getEditor()));
- }
- }
-}
diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractOverrideImplementTest.kt b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractOverrideImplementTest.kt
new file mode 100644
index 00000000000..5171e44d481
--- /dev/null
+++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/AbstractOverrideImplementTest.kt
@@ -0,0 +1,189 @@
+/*
+ * 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.codeInsight
+
+import com.intellij.codeInsight.generation.OverrideImplementUtil
+import com.intellij.codeInsight.generation.PsiMethodMember
+import com.intellij.psi.JavaPsiFacade
+import com.intellij.psi.PsiClassOwner
+import com.intellij.psi.PsiMethod
+import com.intellij.psi.PsiSubstitutor
+import com.intellij.psi.impl.source.PostprocessReformattingAspect
+import com.intellij.psi.search.GlobalSearchScope
+import com.intellij.psi.util.PsiTreeUtil
+import com.intellij.testFramework.LightProjectDescriptor
+import com.intellij.util.SmartList
+import org.jetbrains.kotlin.builtins.KotlinBuiltIns
+import org.jetbrains.kotlin.idea.core.overrideImplement.ImplementMethodsHandler
+import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideImplementMethodsHandler
+import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMemberChooserObject
+import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideMethodsHandler
+import org.jetbrains.kotlin.idea.test.JetLightCodeInsightFixtureTestCase
+import org.jetbrains.kotlin.idea.test.JetLightProjectDescriptor
+import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
+import org.jetbrains.kotlin.psi.JetClassOrObject
+import org.jetbrains.kotlin.test.JetTestUtils
+import org.jetbrains.kotlin.test.TagsTestDataUtil
+import org.jetbrains.kotlin.utils.rethrow
+import org.junit.Assert
+import java.io.File
+import kotlin.test.assertEquals
+
+public abstract class AbstractOverrideImplementTest : JetLightCodeInsightFixtureTestCase() {
+ override fun getProjectDescriptor(): LightProjectDescriptor = JetLightProjectDescriptor.INSTANCE
+
+ protected fun doImplementFileTest() {
+ doFileTest(ImplementMethodsHandler())
+ }
+
+ protected fun doOverrideFileTest() {
+ doFileTest(OverrideMethodsHandler())
+ }
+
+ protected fun doMultiImplementFileTest() {
+ doMultiFileTest(ImplementMethodsHandler())
+ }
+
+ protected fun doMultiOverrideFileTest() {
+ doMultiFileTest(OverrideMethodsHandler())
+ }
+
+ protected fun doImplementDirectoryTest() {
+ doDirectoryTest(ImplementMethodsHandler())
+ }
+
+ protected fun doOverrideDirectoryTest(memberToImplement: String?) {
+ doDirectoryTest(OverrideMethodsHandler(), memberToImplement)
+ }
+
+ protected fun doImplementJavaDirectoryTest(className: String, methodName: String) {
+ myFixture.copyDirectoryToProject(getTestName(true), "")
+ myFixture.configureFromTempProjectFile("foo/JavaClass.java")
+
+ val project = myFixture.project
+
+ val aClass = JavaPsiFacade.getInstance(project).findClass(className, GlobalSearchScope.allScope(project))
+ ?: error("Can't find class: $className")
+
+ val method = aClass.findMethodsByName(methodName, false)[0]
+ ?: error("Can't find method '$methodName' in class $className")
+
+ generateImplementation(method)
+
+ myFixture.checkResultByFile(getTestName(true) + "/foo/JavaClass.java.after")
+ }
+
+ private fun doFileTest(handler: OverrideImplementMethodsHandler) {
+ myFixture.configureByFile(getTestName(true) + ".kt")
+ doOverrideImplement(handler, null)
+ checkResultByFile(getTestName(true) + ".kt.after")
+ }
+
+ private fun doMultiFileTest(handler: OverrideImplementMethodsHandler) {
+ myFixture.configureByFile(getTestName(true) + ".kt")
+ doMultiOverrideImplement(handler)
+ checkResultByFile(getTestName(true) + ".kt.after")
+ }
+
+ protected fun doDirectoryTest(handler: OverrideImplementMethodsHandler) {
+ doDirectoryTest(handler, null)
+ }
+
+ private fun doDirectoryTest(handler: OverrideImplementMethodsHandler, memberToOverride: String?) {
+ myFixture.copyDirectoryToProject(getTestName(true), "")
+ myFixture.configureFromTempProjectFile("foo/Impl.kt")
+ doOverrideImplement(handler, memberToOverride)
+ checkResultByFile(getTestName(true) + "/foo/Impl.kt.after")
+ }
+
+ private fun doOverrideImplement(handler: OverrideImplementMethodsHandler, memberToOverride: String?) {
+ val elementAtCaret = myFixture.file.findElementAt(myFixture.editor.caretModel.offset)
+ val classOrObject = PsiTreeUtil.getParentOfType(elementAtCaret, javaClass())
+ ?: error("Caret should be inside class or object")
+
+ val chooserObjects = handler.collectMethodsToGenerate(classOrObject)
+
+ val singleToOverride = if (memberToOverride == null) {
+ val filtered = chooserObjects.filter { it.descriptor.containingDeclaration != KotlinBuiltIns.getInstance().any }
+ assertEquals(1, filtered.size(), "Invalid number of available chooserObjects for override")
+ filtered.single()
+ }
+ else {
+ var candidateToOverride: OverrideMemberChooserObject? = null
+ for (chooserObject in chooserObjects) {
+ if (chooserObject.descriptor.name.asString() == memberToOverride) {
+ if (candidateToOverride != null) {
+ throw IllegalStateException("more then one descriptor with name $memberToOverride")
+ }
+ candidateToOverride = chooserObject
+ }
+ }
+ if (candidateToOverride == null) {
+ throw IllegalStateException("no chooserObjects to override with name $memberToOverride found")
+ }
+ candidateToOverride!!
+ }
+
+ performGenerateCommand(classOrObject, listOf(singleToOverride))
+ }
+
+ private fun doMultiOverrideImplement(handler: OverrideImplementMethodsHandler) {
+ val elementAtCaret = myFixture.file.findElementAt(myFixture.editor.caretModel.offset)
+ 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() }
+ performGenerateCommand(classOrObject, chooserObjects)
+ }
+
+ private fun generateImplementation(method: PsiMethod) {
+ getProject().executeWriteCommand("") {
+ val aClass = (myFixture.file as PsiClassOwner).classes[0]
+
+ val methodMember = PsiMethodMember(method, PsiSubstitutor.EMPTY)
+
+ OverrideImplementUtil.overrideOrImplementMethodsInRightPlace(myFixture.editor, aClass, SmartList(methodMember), false)
+
+ PostprocessReformattingAspect.getInstance(myFixture.project).doPostponedFormatting()
+ }
+ }
+
+ private fun performGenerateCommand(
+ classOrObject: JetClassOrObject,
+ selectedElements: List) {
+ try {
+ myFixture.project.executeWriteCommand("") {
+ OverrideImplementMethodsHandler.generateMethods(myFixture.editor, classOrObject, selectedElements)
+ }
+ }
+ catch (throwable: Throwable) {
+ throw rethrow(throwable)
+ }
+
+ }
+
+ private fun checkResultByFile(fileName: String) {
+ val expectedFile = File(myFixture.testDataPath, fileName)
+ try {
+ Assert.assertTrue(expectedFile.exists())
+ myFixture.checkResultByFile(fileName)
+ }
+ catch (error: AssertionError) {
+ JetTestUtils.assertEqualsToFile(expectedFile, TagsTestDataUtil.generateTextWithCaretAndSelection(myFixture.editor))
+ }
+ }
+}
diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/OverrideImplementTest.java b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/OverrideImplementTest.java
index 475843b2465..d1646a1ec8e 100644
--- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/OverrideImplementTest.java
+++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/OverrideImplementTest.java
@@ -198,4 +198,16 @@ public final class OverrideImplementTest extends AbstractOverrideImplementTest {
public void testVarArgs() {
doOverrideFileTest();
}
+
+ public void testDoNotOverrideFinal() {
+ doMultiOverrideFileTest();
+ }
+
+ public void testSuperPreference() {
+ doMultiOverrideFileTest();
+ }
+
+ public void testAmbiguousSuper() {
+ doMultiOverrideFileTest();
+ }
}