|
|
|
@@ -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<JetDeclaration> {
|
|
|
|
|
private final List<PsiElement> overriddenMembers = new ArrayList<PsiElement>();
|
|
|
|
|
private final List<PsiElement> overriddenNonOverridableMembers = new ArrayList<PsiElement>();
|
|
|
|
|
private final List<String> containingDeclarationsNames = new ArrayList<String>();
|
|
|
|
|
|
|
|
|
|
public MakeOverriddenMemberOpenFix(@NotNull JetDeclaration declaration) {
|
|
|
|
@@ -55,32 +57,68 @@ public class MakeOverriddenMemberOpenFix extends JetIntentionAction<JetDeclarati
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// When running single test 'isAvailable()' is invoked multiple times, so we need to clear lists.
|
|
|
|
|
overriddenMembers.clear();
|
|
|
|
|
overriddenNonOverridableMembers.clear();
|
|
|
|
|
containingDeclarationsNames.clear();
|
|
|
|
|
|
|
|
|
|
CancelableResolveSession resolveSession = AnalyzerFacadeWithCache.getLazyResolveSessionForFile((JetFile) file);
|
|
|
|
|
DeclarationDescriptor descriptor = resolveSession.resolveToDescriptor(element);
|
|
|
|
|
if (!(descriptor instanceof CallableMemberDescriptor)) return false;
|
|
|
|
|
CallableMemberDescriptor callableMemberDescriptor = (CallableMemberDescriptor) descriptor;
|
|
|
|
|
for (CallableMemberDescriptor overriddenDescriptor : callableMemberDescriptor.getOverriddenDescriptors()) {
|
|
|
|
|
if (!overriddenDescriptor.getModality().isOverridable()) {
|
|
|
|
|
PsiElement overriddenMember =
|
|
|
|
|
BindingContextUtils.descriptorToDeclaration(resolveSession.getBindingContext(), overriddenDescriptor);
|
|
|
|
|
if (overriddenMember == null || !QuickFixUtil.canModifyElement(overriddenMember)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
String containingDeclarationName = overriddenDescriptor.getContainingDeclaration().getName().asString();
|
|
|
|
|
overriddenMembers.add(overriddenMember);
|
|
|
|
|
containingDeclarationsNames.add(containingDeclarationName);
|
|
|
|
|
|
|
|
|
|
for (CallableMemberDescriptor overriddenDescriptor : getAllDeclaredNonOverridableOverriddenDescriptors(
|
|
|
|
|
(CallableMemberDescriptor) descriptor)) {
|
|
|
|
|
assert overriddenDescriptor.getKind() == DECLARATION : "Can only be applied to declarations.";
|
|
|
|
|
PsiElement overriddenMember = descriptorToDeclaration(resolveSession.getBindingContext(), overriddenDescriptor);
|
|
|
|
|
if (overriddenMember == null || !QuickFixUtil.canModifyElement(overriddenMember)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
String containingDeclarationName = overriddenDescriptor.getContainingDeclaration().getName().asString();
|
|
|
|
|
overriddenNonOverridableMembers.add(overriddenMember);
|
|
|
|
|
containingDeclarationsNames.add(containingDeclarationName);
|
|
|
|
|
}
|
|
|
|
|
return overriddenNonOverridableMembers.size() > 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@NotNull
|
|
|
|
|
private static Collection<CallableMemberDescriptor> getAllDeclaredNonOverridableOverriddenDescriptors(
|
|
|
|
|
@NotNull CallableMemberDescriptor callableMemberDescriptor
|
|
|
|
|
) {
|
|
|
|
|
Set<CallableMemberDescriptor> result = Sets.newHashSet();
|
|
|
|
|
Collection<CallableMemberDescriptor>
|
|
|
|
|
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<CallableMemberDescriptor> retainNonOverridableMembers(
|
|
|
|
|
@NotNull Collection<? extends CallableMemberDescriptor> callableMemberDescriptors
|
|
|
|
|
) {
|
|
|
|
|
return ContainerUtil.filter(callableMemberDescriptors, new Condition<CallableMemberDescriptor>() {
|
|
|
|
|
@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<JetDeclarati
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void invoke(@NotNull Project project, Editor editor, JetFile file) throws IncorrectOperationException {
|
|
|
|
|
for (PsiElement overriddenMember : overriddenMembers) {
|
|
|
|
|
for (PsiElement overriddenMember : overriddenNonOverridableMembers) {
|
|
|
|
|
overriddenMember.replace(AddModifierFix.addModifierWithDefaultReplacement(overriddenMember, OPEN_KEYWORD, project, false));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|