MakeOveriddenMembersOpen: J2K, cleanup, de-i18n
This commit is contained in:
@@ -14,7 +14,6 @@ add.init.keyword.in.whole.project=Add 'init' keyword in whole project
|
|||||||
add.init.keyword.in.whole.project.modal.title=Adding 'init' keyword in whole project
|
add.init.keyword.in.whole.project.modal.title=Adding 'init' keyword in whole project
|
||||||
add.init.keyword.in.whole.project.family=Add 'init' keyword in whole project
|
add.init.keyword.in.whole.project.family=Add 'init' keyword in whole project
|
||||||
insert.delegation.call=Insert ''{0}()'' call
|
insert.delegation.call=Insert ''{0}()'' call
|
||||||
make.element.in.classifiers.open=Make ''{0}'' in {1} open
|
|
||||||
make.class.annotation.class=Make ''{0}'' an annotation class
|
make.class.annotation.class=Make ''{0}'' an annotation class
|
||||||
make.class.annotation.class.family=Make Class an Annotation Class
|
make.class.annotation.class.family=Make Class an Annotation Class
|
||||||
add.star.projections=Add ''{0}''
|
add.star.projections=Add ''{0}''
|
||||||
|
|||||||
@@ -14,149 +14,108 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jetbrains.kotlin.idea.quickfix;
|
package org.jetbrains.kotlin.idea.quickfix
|
||||||
|
|
||||||
import com.google.common.collect.Sets;
|
import com.intellij.codeInsight.intention.IntentionAction
|
||||||
import com.intellij.codeInsight.intention.IntentionAction;
|
import com.intellij.openapi.editor.Editor
|
||||||
import com.intellij.openapi.editor.Editor;
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.psi.PsiFile
|
||||||
import com.intellij.openapi.util.Condition;
|
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||||
import com.intellij.psi.PsiElement;
|
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DECLARATION
|
||||||
import com.intellij.psi.PsiFile;
|
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DELEGATION
|
||||||
import com.intellij.util.IncorrectOperationException;
|
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.FAKE_OVERRIDE
|
||||||
import com.intellij.util.containers.ContainerUtil;
|
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.SYNTHESIZED
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor;
|
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
import org.jetbrains.kotlin.lexer.JetTokens.OPEN_KEYWORD
|
||||||
import org.jetbrains.kotlin.diagnostics.Diagnostic;
|
import org.jetbrains.kotlin.psi.JetCallableDeclaration
|
||||||
import org.jetbrains.kotlin.idea.JetBundle;
|
import org.jetbrains.kotlin.psi.JetDeclaration
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionUtils;
|
import org.jetbrains.kotlin.psi.JetFile
|
||||||
import org.jetbrains.kotlin.idea.core.quickfix.QuickFixUtil;
|
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||||
import org.jetbrains.kotlin.psi.JetCallableDeclaration;
|
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||||
import org.jetbrains.kotlin.psi.JetDeclaration;
|
import java.util.*
|
||||||
import org.jetbrains.kotlin.psi.JetFile;
|
|
||||||
|
|
||||||
import java.util.*;
|
public class MakeOverriddenMemberOpenFix(declaration: JetDeclaration) : JetIntentionAction<JetDeclaration>(declaration) {
|
||||||
|
private val overriddenNonOverridableMembers = ArrayList<JetCallableDeclaration>()
|
||||||
|
private val containingDeclarationsNames = ArrayList<String>()
|
||||||
|
|
||||||
import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.*;
|
override fun isAvailable(project: Project, editor: Editor, file: PsiFile): Boolean {
|
||||||
import static org.jetbrains.kotlin.lexer.JetTokens.OPEN_KEYWORD;
|
if (!super.isAvailable(project, editor, file) || file !is JetFile) {
|
||||||
import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.descriptorToDeclaration;
|
return false
|
||||||
|
|
||||||
public class MakeOverriddenMemberOpenFix extends JetIntentionAction<JetDeclaration> {
|
|
||||||
private final List<JetCallableDeclaration> overriddenNonOverridableMembers = new ArrayList<JetCallableDeclaration>();
|
|
||||||
private final List<String> containingDeclarationsNames = new ArrayList<String>();
|
|
||||||
|
|
||||||
public MakeOverriddenMemberOpenFix(@NotNull JetDeclaration declaration) {
|
|
||||||
super(declaration);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
|
|
||||||
if (!super.isAvailable(project, editor, file) || !(file instanceof JetFile)) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// When running single test 'isAvailable()' is invoked multiple times, so we need to clear lists.
|
// When running single test 'isAvailable()' is invoked multiple times, so we need to clear lists.
|
||||||
overriddenNonOverridableMembers.clear();
|
overriddenNonOverridableMembers.clear()
|
||||||
containingDeclarationsNames.clear();
|
containingDeclarationsNames.clear()
|
||||||
|
|
||||||
DeclarationDescriptor descriptor = ResolutionUtils.resolveToDescriptor(element);
|
val descriptor = element.resolveToDescriptor()
|
||||||
if (!(descriptor instanceof CallableMemberDescriptor)) return false;
|
if (descriptor !is CallableMemberDescriptor) return false
|
||||||
|
|
||||||
for (CallableMemberDescriptor overriddenDescriptor : getAllDeclaredNonOverridableOverriddenDescriptors(
|
for (overriddenDescriptor in getAllDeclaredNonOverridableOverriddenDescriptors(
|
||||||
(CallableMemberDescriptor) descriptor)) {
|
descriptor)) {
|
||||||
assert overriddenDescriptor.getKind() == DECLARATION : "Can only be applied to declarations.";
|
assert(overriddenDescriptor.kind == DECLARATION) { "Can only be applied to declarations." }
|
||||||
PsiElement overriddenMember = descriptorToDeclaration(overriddenDescriptor);
|
val overriddenMember = DescriptorToSourceUtils.descriptorToDeclaration(overriddenDescriptor)
|
||||||
if (overriddenMember == null || !QuickFixUtil.canModifyElement(overriddenMember) || !(overriddenMember instanceof JetCallableDeclaration)) {
|
if (overriddenMember == null || !QuickFixUtil.canModifyElement(overriddenMember) || overriddenMember !is JetCallableDeclaration) {
|
||||||
return false;
|
return false
|
||||||
}
|
}
|
||||||
String containingDeclarationName = overriddenDescriptor.getContainingDeclaration().getName().asString();
|
val containingDeclarationName = overriddenDescriptor.containingDeclaration.name.asString()
|
||||||
overriddenNonOverridableMembers.add((JetCallableDeclaration) overriddenMember);
|
overriddenNonOverridableMembers.add(overriddenMember)
|
||||||
containingDeclarationsNames.add(containingDeclarationName);
|
containingDeclarationsNames.add(containingDeclarationName)
|
||||||
}
|
}
|
||||||
return overriddenNonOverridableMembers.size() > 0;
|
return overriddenNonOverridableMembers.size() > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
override fun getText(): String {
|
||||||
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 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 (overriddenNonOverridableMembers.size() == 1) {
|
if (overriddenNonOverridableMembers.size() == 1) {
|
||||||
return JetBundle.message("make.element.modifier", containingDeclarationsNames.get(0) + "." + element.getName(), OPEN_KEYWORD);
|
val name = containingDeclarationsNames.get(0) + "." + element.name
|
||||||
|
return "Make $name $OPEN_KEYWORD"
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder declarations = new StringBuilder();
|
Collections.sort(containingDeclarationsNames)
|
||||||
Collections.sort(containingDeclarationsNames);
|
val declarations = containingDeclarationsNames.subList(0, containingDeclarationsNames.size()-1).join(", ") + " and " +
|
||||||
for (int i = 0; i < containingDeclarationsNames.size() - 2; i++) {
|
containingDeclarationsNames.last()
|
||||||
declarations.append(containingDeclarationsNames.get(i));
|
return "Make '${element.name}' in $declarations open"
|
||||||
declarations.append(", ");
|
|
||||||
}
|
|
||||||
declarations.append(containingDeclarationsNames.get(containingDeclarationsNames.size() - 2));
|
|
||||||
declarations.append(" and ");
|
|
||||||
declarations.append(containingDeclarationsNames.get(containingDeclarationsNames.size() - 1));
|
|
||||||
return JetBundle.message("make.element.in.classifiers.open", element.getName(), declarations.toString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
override fun getFamilyName(): String = "Add Modifier"
|
||||||
@Override
|
|
||||||
public String getFamilyName() {
|
|
||||||
return JetBundle.message("add.modifier.family");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
override fun invoke(project: Project, editor: Editor?, file: JetFile) {
|
||||||
public void invoke(@NotNull Project project, Editor editor, JetFile file) throws IncorrectOperationException {
|
for (overriddenMember in overriddenNonOverridableMembers) {
|
||||||
for (JetCallableDeclaration overriddenMember : overriddenNonOverridableMembers) {
|
overriddenMember.addModifier(OPEN_KEYWORD)
|
||||||
overriddenMember.addModifier(OPEN_KEYWORD);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
companion object : JetSingleIntentionActionFactory() {
|
||||||
public static JetSingleIntentionActionFactory createFactory() {
|
|
||||||
return new JetSingleIntentionActionFactory() {
|
private fun getAllDeclaredNonOverridableOverriddenDescriptors(
|
||||||
@Nullable
|
callableMemberDescriptor: CallableMemberDescriptor): Collection<CallableMemberDescriptor> {
|
||||||
@Override
|
val result = hashSetOf<CallableMemberDescriptor>()
|
||||||
public IntentionAction createAction(@NotNull Diagnostic diagnostic) {
|
val nonOverridableOverriddenDescriptors = retainNonOverridableMembers(callableMemberDescriptor.overriddenDescriptors)
|
||||||
JetDeclaration declaration = QuickFixUtil.getParentElementOfType(diagnostic, JetDeclaration.class);
|
for (overriddenDescriptor in nonOverridableOverriddenDescriptors) {
|
||||||
assert declaration != null;
|
when (overriddenDescriptor.kind) {
|
||||||
return new MakeOverriddenMemberOpenFix(declaration);
|
DECLARATION ->
|
||||||
|
result.add(overriddenDescriptor)
|
||||||
|
|
||||||
|
FAKE_OVERRIDE, DELEGATION ->
|
||||||
|
result.addAll(getAllDeclaredNonOverridableOverriddenDescriptors(overriddenDescriptor))
|
||||||
|
|
||||||
|
SYNTHESIZED -> {} /* do nothing */
|
||||||
|
|
||||||
|
else -> throw UnsupportedOperationException("Unexpected callable kind ${overriddenDescriptor.kind}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun retainNonOverridableMembers(
|
||||||
|
callableMemberDescriptors: Collection<CallableMemberDescriptor>): Collection<CallableMemberDescriptor> {
|
||||||
|
return callableMemberDescriptors.filter { !it.modality.isOverridable }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
||||||
|
val declaration = diagnostic.psiElement.getNonStrictParentOfType<JetDeclaration>()!!
|
||||||
|
return MakeOverriddenMemberOpenFix(declaration)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ public class QuickFixRegistrar : QuickFixContributor {
|
|||||||
FINAL_SUPERTYPE.registerFactory(addOpenModifierToClassDeclarationFix)
|
FINAL_SUPERTYPE.registerFactory(addOpenModifierToClassDeclarationFix)
|
||||||
FINAL_UPPER_BOUND.registerFactory(addOpenModifierToClassDeclarationFix)
|
FINAL_UPPER_BOUND.registerFactory(addOpenModifierToClassDeclarationFix)
|
||||||
|
|
||||||
OVERRIDING_FINAL_MEMBER.registerFactory(MakeOverriddenMemberOpenFix.createFactory())
|
OVERRIDING_FINAL_MEMBER.registerFactory(MakeOverriddenMemberOpenFix)
|
||||||
|
|
||||||
PARAMETER_NAME_CHANGED_ON_OVERRIDE.registerFactory(RenameParameterToMatchOverriddenMethodFix.createFactory())
|
PARAMETER_NAME_CHANGED_ON_OVERRIDE.registerFactory(RenameParameterToMatchOverriddenMethodFix.createFactory())
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user