mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-26 19:06:24 +07:00
add quickfix to implement abstract methods for enum constants without class initializer (IDEA-59807)
This commit is contained in:
+2
-2
@@ -1066,10 +1066,10 @@ public class GenericsHighlightUtil {
|
||||
}
|
||||
|
||||
static void checkEnumConstantForConstructorProblems(PsiEnumConstant enumConstant, final HighlightInfoHolder holder) {
|
||||
PsiClass containingClass = enumConstant.getContainingClass();
|
||||
if (enumConstant.getInitializingClass() == null) {
|
||||
PsiClass containingClass = enumConstant.getContainingClass(); if (enumConstant.getInitializingClass() == null) {
|
||||
HighlightInfo highlightInfo = HighlightClassUtil.checkInstantiationOfAbstractClass(containingClass, enumConstant.getNameIdentifier());
|
||||
if (highlightInfo != null) {
|
||||
QuickFixAction.registerQuickFixAction(highlightInfo, QUICK_FIX_FACTORY.createImplementMethodsFix(enumConstant));
|
||||
holder.add(highlightInfo);
|
||||
return;
|
||||
}
|
||||
|
||||
+55
-9
@@ -18,19 +18,33 @@ package com.intellij.codeInsight.daemon.impl.quickfix;
|
||||
import com.intellij.codeInsight.CodeInsightUtilBase;
|
||||
import com.intellij.codeInsight.daemon.QuickFixBundle;
|
||||
import com.intellij.codeInsight.generation.OverrideImplementUtil;
|
||||
import com.intellij.codeInsight.generation.PsiMethodMember;
|
||||
import com.intellij.codeInsight.intention.impl.ImplementAbstractMethodHandler;
|
||||
import com.intellij.codeInspection.IntentionAndQuickFixAction;
|
||||
import com.intellij.featureStatistics.FeatureUsageTracker;
|
||||
import com.intellij.ide.util.MemberChooser;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.Result;
|
||||
import com.intellij.openapi.command.WriteCommandAction;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.infos.CandidateInfo;
|
||||
import com.intellij.psi.util.MethodSignature;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class ImplementMethodsFix extends IntentionAndQuickFixAction {
|
||||
private final PsiClass myClass;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.TreeMap;
|
||||
|
||||
public ImplementMethodsFix(PsiClass aClass) {
|
||||
myClass = aClass;
|
||||
public class ImplementMethodsFix extends IntentionAndQuickFixAction {
|
||||
private final PsiElement myPsiElement;
|
||||
public ImplementMethodsFix(PsiElement aClass) {
|
||||
myPsiElement = aClass;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -44,12 +58,44 @@ public class ImplementMethodsFix extends IntentionAndQuickFixAction {
|
||||
}
|
||||
|
||||
public boolean isAvailable(@NotNull final Project project, final Editor editor, final PsiFile file) {
|
||||
return myClass.isValid() && myClass.getManager().isInProject(myClass);
|
||||
return myPsiElement.isValid() && myPsiElement.getManager().isInProject(myPsiElement);
|
||||
}
|
||||
|
||||
public void applyFix(final Project project, final PsiFile file, @Nullable final Editor editor) {
|
||||
if (editor == null || !CodeInsightUtilBase.prepareFileForWrite(myClass.getContainingFile())) return;
|
||||
OverrideImplementUtil.chooseAndImplementMethods(project, editor, myClass);
|
||||
if (editor == null || !CodeInsightUtilBase.prepareFileForWrite(myPsiElement.getContainingFile())) return;
|
||||
if (myPsiElement instanceof PsiEnumConstant) {
|
||||
FeatureUsageTracker.getInstance().triggerFeatureUsed("codeassists.overrideimplement");
|
||||
final TreeMap<MethodSignature, CandidateInfo> result =
|
||||
new TreeMap<MethodSignature, CandidateInfo>(new OverrideImplementUtil.MethodSignatureComparator());
|
||||
final HashMap<MethodSignature, PsiMethod> abstracts = new HashMap<MethodSignature, PsiMethod>();
|
||||
for (PsiMethod method : ((PsiEnumConstant)myPsiElement).getContainingClass().getMethods()) {
|
||||
if (method.hasModifierProperty(PsiModifier.ABSTRACT)) {
|
||||
abstracts.put(method.getHierarchicalMethodSignature(), method);
|
||||
}
|
||||
}
|
||||
final HashMap<MethodSignature, PsiMethod> finals = new HashMap<MethodSignature, PsiMethod>();
|
||||
final HashMap<MethodSignature, PsiMethod> concretes = new HashMap<MethodSignature, PsiMethod>();
|
||||
OverrideImplementUtil.collectMethodsToImplement(null, abstracts, finals, concretes, result);
|
||||
|
||||
final MemberChooser<PsiMethodMember> chooser =
|
||||
OverrideImplementUtil.showOverrideImplementChooser(editor, myPsiElement, true, result.values(), Collections.<CandidateInfo>emptyList());
|
||||
if (chooser == null) return;
|
||||
|
||||
final List<PsiMethodMember> selectedElements = chooser.getSelectedElements();
|
||||
if (selectedElements == null || selectedElements.isEmpty()) return;
|
||||
|
||||
new WriteCommandAction(project, file) {
|
||||
protected void run(final Result result) throws Throwable {
|
||||
final PsiClass psiClass = ImplementAbstractMethodHandler.addClassInitializer((PsiEnumConstant)myPsiElement);
|
||||
OverrideImplementUtil.overrideOrImplementMethodsInRightPlace(editor, psiClass, selectedElements, chooser.isCopyJavadoc(),
|
||||
chooser.isInsertOverrideAnnotation());
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
else {
|
||||
OverrideImplementUtil.chooseAndImplementMethods(project, editor, (PsiClass)myPsiElement);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public boolean startInWriteAction() {
|
||||
|
||||
@@ -125,57 +125,9 @@ public class OverrideImplementUtil {
|
||||
}
|
||||
}
|
||||
|
||||
Map<MethodSignature, CandidateInfo> result = new TreeMap<MethodSignature,CandidateInfo>(new Comparator<MethodSignature>() {
|
||||
// signatures should appear in the order of declaration
|
||||
public int compare(MethodSignature o1, MethodSignature o2) {
|
||||
if (o1 instanceof MethodSignatureBackedByPsiMethod && o2 instanceof MethodSignatureBackedByPsiMethod) {
|
||||
PsiMethod m1 = ((MethodSignatureBackedByPsiMethod)o1).getMethod();
|
||||
PsiMethod m2 = ((MethodSignatureBackedByPsiMethod)o2).getMethod();
|
||||
PsiElement p1 = m1.getParent();
|
||||
PsiElement p2 = m2.getParent();
|
||||
if (p1 instanceof PsiClass && p2 instanceof PsiClass) {
|
||||
final PsiClass c1 = (PsiClass)p1;
|
||||
final PsiClass c2 = (PsiClass)p2;
|
||||
|
||||
if (c1 == c2) {
|
||||
final List<PsiMethod> methods = Arrays.asList(c1.getMethods());
|
||||
return methods.indexOf(m1) - methods.indexOf(m2);
|
||||
}
|
||||
|
||||
if (c1.isInheritor(c2, true)) return -1;
|
||||
if (c2.isInheritor(c1, true)) return 1;
|
||||
|
||||
return StringUtil.notNullize(c1.getName()).compareTo(StringUtil.notNullize(c2.getName()));
|
||||
}
|
||||
return m1.getTextOffset() - m2.getTextOffset();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
final Map<MethodSignature, CandidateInfo> result = new TreeMap<MethodSignature,CandidateInfo>(new MethodSignatureComparator());
|
||||
if (toImplement || aClass.isInterface()) {
|
||||
for (Map.Entry<MethodSignature, PsiMethod> entry : abstracts.entrySet()) {
|
||||
MethodSignature signature = entry.getKey();
|
||||
PsiMethod abstractOne = entry.getValue();
|
||||
PsiMethod concrete = concretes.get(signature);
|
||||
if (concrete == null
|
||||
|| PsiUtil.getAccessLevel(concrete.getModifierList()) < PsiUtil.getAccessLevel(abstractOne.getModifierList())
|
||||
|| !abstractOne.getContainingClass().isInterface() && abstractOne.getContainingClass().isInheritor(concrete.getContainingClass(), true)) {
|
||||
if (finals.get(signature) == null) {
|
||||
PsiSubstitutor subst = GenerateMembersUtil.correctSubstitutor(abstractOne, signature.getSubstitutor());
|
||||
CandidateInfo info = new CandidateInfo(abstractOne, subst);
|
||||
result.put(signature, info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (final MethodImplementor implementor : getImplementors()) {
|
||||
for (final PsiMethod method : implementor.getMethodsToImplement(aClass)) {
|
||||
MethodSignature signature = MethodSignatureUtil.createMethodSignature(method.getName(), method.getParameterList(),
|
||||
method.getTypeParameterList(), PsiSubstitutor.EMPTY);
|
||||
CandidateInfo info = new CandidateInfo(method, PsiSubstitutor.EMPTY);
|
||||
result.put(signature, info);
|
||||
}
|
||||
}
|
||||
collectMethodsToImplement(aClass, abstracts, finals, concretes, result);
|
||||
}
|
||||
else {
|
||||
for (Map.Entry<MethodSignature, PsiMethod> entry : concretes.entrySet()) {
|
||||
@@ -196,6 +148,36 @@ public class OverrideImplementUtil {
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void collectMethodsToImplement(PsiClass aClass,
|
||||
Map<MethodSignature, PsiMethod> abstracts,
|
||||
Map<MethodSignature, PsiMethod> finals,
|
||||
Map<MethodSignature, PsiMethod> concretes,
|
||||
Map<MethodSignature, CandidateInfo> result) {
|
||||
for (Map.Entry<MethodSignature, PsiMethod> entry : abstracts.entrySet()) {
|
||||
MethodSignature signature = entry.getKey();
|
||||
PsiMethod abstractOne = entry.getValue();
|
||||
PsiMethod concrete = concretes.get(signature);
|
||||
if (concrete == null
|
||||
|| PsiUtil.getAccessLevel(concrete.getModifierList()) < PsiUtil.getAccessLevel(abstractOne.getModifierList())
|
||||
|| !abstractOne.getContainingClass().isInterface() && abstractOne.getContainingClass().isInheritor(concrete.getContainingClass(), true)) {
|
||||
if (finals.get(signature) == null) {
|
||||
PsiSubstitutor subst = GenerateMembersUtil.correctSubstitutor(abstractOne, signature.getSubstitutor());
|
||||
CandidateInfo info = new CandidateInfo(abstractOne, subst);
|
||||
result.put(signature, info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (final MethodImplementor implementor : getImplementors()) {
|
||||
for (final PsiMethod method : implementor.getMethodsToImplement(aClass)) {
|
||||
MethodSignature signature = MethodSignatureUtil.createMethodSignature(method.getName(), method.getParameterList(),
|
||||
method.getTypeParameterList(), PsiSubstitutor.EMPTY);
|
||||
CandidateInfo info = new CandidateInfo(method, PsiSubstitutor.EMPTY);
|
||||
result.put(signature, info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean preferLeftForImplement(PsiMethod left, PsiMethod right) {
|
||||
if (PsiUtil.getAccessLevel(left.getModifierList()) > PsiUtil.getAccessLevel(right.getModifierList())) return true;
|
||||
if (!left.getContainingClass().isInterface()) return true;
|
||||
@@ -497,7 +479,7 @@ public class OverrideImplementUtil {
|
||||
|
||||
@Nullable
|
||||
public static MemberChooser<PsiMethodMember> showOverrideImplementChooser(Editor editor,
|
||||
final PsiClass aClass,
|
||||
final PsiElement aClass,
|
||||
final boolean toImplement,
|
||||
Collection<CandidateInfo> candidates,
|
||||
Collection<CandidateInfo> secondary) {
|
||||
@@ -568,7 +550,7 @@ public class OverrideImplementUtil {
|
||||
});
|
||||
}
|
||||
|
||||
private static void registerHandlerForComplementaryAction(final Project project, final Editor editor, final PsiClass aClass,
|
||||
private static void registerHandlerForComplementaryAction(final Project project, final Editor editor, final PsiElement aClass,
|
||||
final boolean toImplement,
|
||||
final MemberChooser<PsiMethodMember> chooser) {
|
||||
final JComponent preferredFocusedComponent = chooser.getPreferredFocusedComponent();
|
||||
@@ -725,4 +707,32 @@ public class OverrideImplementUtil {
|
||||
boolean insert = CodeStyleSettingsManager.getSettings(aClass.getProject()).INSERT_OVERRIDE_ANNOTATION;
|
||||
return overrideOrImplementMethodCandidates(aClass, candidatesToImplement, copyJavadoc, insert);
|
||||
}
|
||||
|
||||
public static class MethodSignatureComparator implements Comparator<MethodSignature> {
|
||||
// signatures should appear in the order of declaration
|
||||
public int compare(MethodSignature o1, MethodSignature o2) {
|
||||
if (o1 instanceof MethodSignatureBackedByPsiMethod && o2 instanceof MethodSignatureBackedByPsiMethod) {
|
||||
PsiMethod m1 = ((MethodSignatureBackedByPsiMethod)o1).getMethod();
|
||||
PsiMethod m2 = ((MethodSignatureBackedByPsiMethod)o2).getMethod();
|
||||
PsiElement p1 = m1.getParent();
|
||||
PsiElement p2 = m2.getParent();
|
||||
if (p1 instanceof PsiClass && p2 instanceof PsiClass) {
|
||||
final PsiClass c1 = (PsiClass)p1;
|
||||
final PsiClass c2 = (PsiClass)p2;
|
||||
|
||||
if (c1 == c2) {
|
||||
final List<PsiMethod> methods = Arrays.asList(c1.getMethods());
|
||||
return methods.indexOf(m1) - methods.indexOf(m2);
|
||||
}
|
||||
|
||||
if (c1.isInheritor(c2, true)) return -1;
|
||||
if (c2.isInheritor(c1, true)) return 1;
|
||||
|
||||
return StringUtil.notNullize(c1.getName()).compareTo(StringUtil.notNullize(c2.getName()));
|
||||
}
|
||||
return m1.getTextOffset() - m2.getTextOffset();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -162,7 +162,7 @@ public class ImplementAbstractMethodHandler {
|
||||
}, CodeInsightBundle.message("intention.implement.abstract.method.command.name"), null);
|
||||
}
|
||||
|
||||
static PsiClass addClassInitializer(PsiEnumConstant enumConstant) {
|
||||
public static PsiClass addClassInitializer(PsiEnumConstant enumConstant) {
|
||||
final PsiEnumConstant constantFromText = JavaPsiFacade.getElementFactory(enumConstant.getProject()).createEnumConstantFromText(
|
||||
enumConstant.getName() + "{}", enumConstant);
|
||||
final PsiEnumConstant replace = (PsiEnumConstant)enumConstant.replace(constantFromText);
|
||||
|
||||
+4
@@ -60,6 +60,10 @@ public class QuickFixFactoryImpl extends QuickFixFactory {
|
||||
return new ImplementMethodsFix(aClass);
|
||||
}
|
||||
|
||||
public IntentionAction createImplementMethodsFix(@NotNull PsiElement psiElement) {
|
||||
return new ImplementMethodsFix(psiElement);
|
||||
}
|
||||
|
||||
public IntentionAction createMethodThrowsFix(@NotNull PsiMethod method,
|
||||
@NotNull PsiClassType exceptionClass,
|
||||
boolean shouldThrow,
|
||||
|
||||
@@ -42,7 +42,11 @@ public abstract class QuickFixFactory {
|
||||
public abstract IntentionAction createAddMethodFix(@NotNull PsiMethod method, @NotNull PsiClass toClass);
|
||||
public abstract IntentionAction createAddMethodFix(@NotNull String methodText, @NotNull PsiClass toClass, String... exceptions);
|
||||
|
||||
public abstract IntentionAction createImplementMethodsFix(@NotNull PsiClass aClass);
|
||||
/**
|
||||
* @param psiElement psiClass or enum constant without class initializer
|
||||
*/
|
||||
public abstract IntentionAction createImplementMethodsFix(@NotNull PsiElement psiElement);
|
||||
public abstract IntentionAction createImplementMethodsFix(@NotNull PsiClass psiElement);
|
||||
public abstract IntentionAction createMethodThrowsFix(@NotNull PsiMethod method, @NotNull PsiClassType exceptionClass, boolean shouldThrow, boolean showContainingClass);
|
||||
public abstract IntentionAction createAddDefaultConstructorFix(@NotNull PsiClass aClass);
|
||||
public abstract IntentionAction createMethodParameterTypeFix(@NotNull PsiMethod method, int index, @NotNull PsiType newType, boolean fixWholeHierarchy);
|
||||
|
||||
Reference in New Issue
Block a user