diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/MakeOverriddenMemberOpenFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/MakeOverriddenMemberOpenFix.java index d1651cb1f62..83068e30b59 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/MakeOverriddenMemberOpenFix.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/MakeOverriddenMemberOpenFix.java @@ -16,12 +16,15 @@ package org.jetbrains.jet.plugin.quickfix; +import com.google.common.collect.Sets; import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Condition; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor; @@ -29,19 +32,18 @@ import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.diagnostics.Diagnostic; import org.jetbrains.jet.lang.psi.JetDeclaration; import org.jetbrains.jet.lang.psi.JetFile; -import org.jetbrains.jet.lang.resolve.BindingContextUtils; import org.jetbrains.jet.plugin.JetBundle; import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache; import org.jetbrains.jet.plugin.project.CancelableResolveSession; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import java.util.*; +import static org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor.Kind.*; +import static org.jetbrains.jet.lang.resolve.BindingContextUtils.descriptorToDeclaration; import static org.jetbrains.jet.lexer.JetTokens.OPEN_KEYWORD; public class MakeOverriddenMemberOpenFix extends JetIntentionAction { - private final List overriddenMembers = new ArrayList(); + private final List overriddenNonOverridableMembers = new ArrayList(); private final List containingDeclarationsNames = new ArrayList(); public MakeOverriddenMemberOpenFix(@NotNull JetDeclaration declaration) { @@ -55,32 +57,68 @@ public class MakeOverriddenMemberOpenFix extends JetIntentionAction 0; + } + + @NotNull + private static Collection getAllDeclaredNonOverridableOverriddenDescriptors( + @NotNull CallableMemberDescriptor callableMemberDescriptor + ) { + Set result = Sets.newHashSet(); + Collection + nonOverridableOverriddenDescriptors = retainNonOverridableMembers(callableMemberDescriptor.getOverriddenDescriptors()); + for (CallableMemberDescriptor overriddenDescriptor : nonOverridableOverriddenDescriptors) { + CallableMemberDescriptor.Kind kind = overriddenDescriptor.getKind(); + if (kind == DECLARATION) { + result.add(overriddenDescriptor); + } + else if (kind == FAKE_OVERRIDE || kind == DELEGATION) { + result.addAll(getAllDeclaredNonOverridableOverriddenDescriptors(overriddenDescriptor)); + } + else if (kind == SYNTHESIZED) { + // do nothing, final synthesized members can't be made open + } + else { + throw new UnsupportedOperationException("Unexpected callable kind " + kind); } } - return overriddenMembers.size() > 0; + return result; + } + + @NotNull + private static Collection retainNonOverridableMembers( + @NotNull Collection callableMemberDescriptors + ) { + return ContainerUtil.filter(callableMemberDescriptors, new Condition() { + @Override + public boolean value(CallableMemberDescriptor descriptor) { + return !descriptor.getModality().isOverridable(); + } + }); } @NotNull @Override public String getText() { - if (overriddenMembers.size() == 1) { + if (overriddenNonOverridableMembers.size() == 1) { return JetBundle.message("make.element.modifier", containingDeclarationsNames.get(0) + "." + element.getName(), OPEN_KEYWORD); } @@ -104,7 +142,7 @@ public class MakeOverriddenMemberOpenFix extends JetIntentionAction fun foo() { + } +} diff --git a/idea/testData/quickfix/override/beforeOverridingFakeOverride.kt b/idea/testData/quickfix/override/beforeOverridingFakeOverride.kt new file mode 100644 index 00000000000..db622498481 --- /dev/null +++ b/idea/testData/quickfix/override/beforeOverridingFakeOverride.kt @@ -0,0 +1,18 @@ +// "Make XX.foo open" "true" +trait X { + fun foo() +} + +trait XX : X { + override final fun foo() { + + } +} + +trait Y : X, XX { +} + +class B() : Y { + override fun foo() { + } +} diff --git a/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java index 57cfaea5348..c89a4b16171 100644 --- a/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java @@ -1017,6 +1017,16 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { doTest("idea/testData/quickfix/override/beforeOverriddingMultipleFinalMethods.kt"); } + @TestMetadata("beforeOverridingDelegatedMethod.kt") + public void testOverridingDelegatedMethod() throws Exception { + doTest("idea/testData/quickfix/override/beforeOverridingDelegatedMethod.kt"); + } + + @TestMetadata("beforeOverridingFakeOverride.kt") + public void testOverridingFakeOverride() throws Exception { + doTest("idea/testData/quickfix/override/beforeOverridingFakeOverride.kt"); + } + @TestMetadata("beforeOverridingFinalJavaMethod.kt") public void testOverridingFinalJavaMethod() throws Exception { doTest("idea/testData/quickfix/override/beforeOverridingFinalJavaMethod.kt");