mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
expand implement methods fix availability for new Runnable()<caret> (IDEA-74043 )
This commit is contained in:
+63
-2
@@ -22,15 +22,22 @@
|
||||
package com.intellij.codeInsight.daemon.impl.analysis;
|
||||
|
||||
import com.intellij.codeInsight.ClassUtil;
|
||||
import com.intellij.codeInsight.CodeInsightUtilBase;
|
||||
import com.intellij.codeInsight.ExceptionUtil;
|
||||
import com.intellij.codeInsight.daemon.JavaErrorMessages;
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfoType;
|
||||
import com.intellij.codeInsight.daemon.impl.RefCountHolder;
|
||||
import com.intellij.codeInsight.daemon.impl.quickfix.*;
|
||||
import com.intellij.codeInsight.generation.OverrideImplementUtil;
|
||||
import com.intellij.codeInsight.generation.PsiMethodMember;
|
||||
import com.intellij.codeInsight.intention.IntentionAction;
|
||||
import com.intellij.codeInsight.intention.QuickFixFactory;
|
||||
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.editor.Editor;
|
||||
import com.intellij.openapi.fileTypes.StdFileTypes;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleUtil;
|
||||
@@ -118,12 +125,21 @@ public class HighlightClassUtil {
|
||||
if (aClass.hasModifierProperty(PsiModifier.ABSTRACT)) {
|
||||
String baseClassName = aClass.getName();
|
||||
String message = JavaErrorMessages.message("abstract.cannot.be.instantiated", baseClassName);
|
||||
errorResult = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, highlightElement, message);
|
||||
if (!aClass.isInterface() && ClassUtil.getAnyAbstractMethod(aClass) == null) {
|
||||
PsiElement parent = highlightElement.getParent();
|
||||
if (parent instanceof PsiNewExpression) {
|
||||
errorResult = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, parent, message);
|
||||
} else {
|
||||
errorResult = HighlightInfo.createHighlightInfo(HighlightInfoType.ERROR, highlightElement, message);
|
||||
}
|
||||
final PsiMethod anyAbstractMethod = ClassUtil.getAnyAbstractMethod(aClass);
|
||||
if (!aClass.isInterface() && anyAbstractMethod == null) {
|
||||
// suggest to make not abstract only if possible
|
||||
IntentionAction fix = QUICK_FIX_FACTORY.createModifierListFix(aClass, PsiModifier.ABSTRACT, false, false);
|
||||
QuickFixAction.registerQuickFixAction(errorResult, fix);
|
||||
}
|
||||
if (anyAbstractMethod != null && parent instanceof PsiNewExpression) {
|
||||
QuickFixAction.registerQuickFixAction(errorResult, new ImplementAbstractClassMethodsFix(parent));
|
||||
}
|
||||
}
|
||||
return errorResult;
|
||||
}
|
||||
@@ -863,4 +879,49 @@ public class HighlightClassUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class ImplementAbstractClassMethodsFix extends ImplementMethodsFix {
|
||||
public ImplementAbstractClassMethodsFix(PsiElement highlightElement) {
|
||||
super(highlightElement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable(@NotNull Project project,
|
||||
@NotNull PsiFile file,
|
||||
@NotNull PsiElement startElement,
|
||||
@NotNull PsiElement endElement) {
|
||||
return startElement instanceof PsiNewExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(@NotNull final Project project,
|
||||
@NotNull PsiFile file,
|
||||
@Nullable("is null when called from inspection") final Editor editor,
|
||||
@NotNull final PsiElement startElement,
|
||||
@NotNull PsiElement endElement) {
|
||||
final PsiFile containingFile = startElement.getContainingFile();
|
||||
if (editor == null || !CodeInsightUtilBase.prepareFileForWrite(containingFile)) return;
|
||||
PsiJavaCodeReferenceElement classReference = ((PsiNewExpression)startElement).getClassReference();
|
||||
final MemberChooser<PsiMethodMember> chooser = chooseMethodsToImplement(editor, startElement, (PsiClass)classReference.resolve());
|
||||
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 {
|
||||
PsiNewExpression newExpression =
|
||||
(PsiNewExpression)JavaPsiFacade.getElementFactory(project).createExpressionFromText(startElement.getText() + "{}", startElement);
|
||||
newExpression = (PsiNewExpression)startElement.replace(newExpression);
|
||||
final PsiClass psiClass = newExpression.getAnonymousClass();
|
||||
PsiSubstitutor superClassSubstitutor = TypeConversionUtil
|
||||
.getSuperClassSubstitutor(((PsiAnonymousClass)psiClass).getBaseClassType().resolve(), psiClass, PsiSubstitutor.EMPTY);
|
||||
for (PsiMethodMember selectedElement : selectedElements) {
|
||||
selectedElement.setSubstitutor(superClassSubstitutor);
|
||||
}
|
||||
OverrideImplementUtil.overrideOrImplementMethodsInRightPlace(editor, psiClass, selectedElements, chooser.isCopyJavadoc(),
|
||||
chooser.isInsertOverrideAnnotation());
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+24
-16
@@ -30,11 +30,11 @@ import com.intellij.openapi.project.Project;
|
||||
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;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.TreeMap;
|
||||
|
||||
@@ -73,21 +73,7 @@ public class ImplementMethodsFix extends LocalQuickFixAndIntentionActionOnPsiEle
|
||||
|
||||
if (editor == null || !CodeInsightUtilBase.prepareFileForWrite(myPsiElement.getContainingFile())) return;
|
||||
if (myPsiElement instanceof PsiEnumConstant) {
|
||||
FeatureUsageTracker.getInstance().triggerFeatureUsed(ProductivityFeatureNames.CODEASSISTS_OVERRIDE_IMPLEMENT);
|
||||
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());
|
||||
final MemberChooser<PsiMethodMember> chooser = chooseMethodsToImplement(editor, startElement, ((PsiEnumConstant)myPsiElement).getContainingClass());
|
||||
if (chooser == null) return;
|
||||
|
||||
final List<PsiMethodMember> selectedElements = chooser.getSelectedElements();
|
||||
@@ -111,4 +97,26 @@ public class ImplementMethodsFix extends LocalQuickFixAndIntentionActionOnPsiEle
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
protected static MemberChooser<PsiMethodMember> chooseMethodsToImplement(Editor editor, PsiElement startElement, PsiClass aClass) {
|
||||
FeatureUsageTracker.getInstance().triggerFeatureUsed(ProductivityFeatureNames.CODEASSISTS_OVERRIDE_IMPLEMENT);
|
||||
|
||||
final TreeMap<MethodSignature, CandidateInfo> result =
|
||||
new TreeMap<MethodSignature, CandidateInfo>(new OverrideImplementUtil.MethodSignatureComparator());
|
||||
final HashMap<MethodSignature, PsiMethod> abstracts = new HashMap<MethodSignature, PsiMethod>();
|
||||
final HashMap<MethodSignature, PsiMethod> finals = new HashMap<MethodSignature, PsiMethod>();
|
||||
final HashMap<MethodSignature, PsiMethod> concretes = new HashMap<MethodSignature, PsiMethod>();
|
||||
|
||||
for (PsiMethod method : aClass.getMethods()) {
|
||||
if (method.hasModifierProperty(PsiModifier.ABSTRACT)) {
|
||||
abstracts.put(method.getHierarchicalMethodSignature(), method);
|
||||
}
|
||||
}
|
||||
|
||||
OverrideImplementUtil.collectMethodsToImplement(null, abstracts, finals, concretes, result);
|
||||
|
||||
return OverrideImplementUtil
|
||||
.showOverrideImplementChooser(editor, startElement, true, result.values(), Collections.<CandidateInfo>emptyList());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ import com.intellij.psi.util.PsiFormatUtil;
|
||||
*/
|
||||
public abstract class PsiElementClassMember<T extends PsiDocCommentOwner> extends PsiDocCommentOwnerMemberChooserObject implements ClassMemberWithElement {
|
||||
private final T myPsiMember;
|
||||
private final PsiSubstitutor mySubstitutor;
|
||||
private PsiSubstitutor mySubstitutor;
|
||||
|
||||
protected PsiElementClassMember(final T psiMember, String text) {
|
||||
this(psiMember, PsiSubstitutor.EMPTY, text);
|
||||
@@ -46,6 +46,10 @@ public abstract class PsiElementClassMember<T extends PsiDocCommentOwner> extend
|
||||
return mySubstitutor;
|
||||
}
|
||||
|
||||
public void setSubstitutor(PsiSubstitutor substitutor) {
|
||||
mySubstitutor = substitutor;
|
||||
}
|
||||
|
||||
public MemberChooserObject getParentNodeDelegate() {
|
||||
final PsiClass psiClass = getContainingClass();
|
||||
final String text = PsiFormatUtil.formatClass(psiClass, PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_FQ_NAME);
|
||||
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
// instantiate abstract
|
||||
public class a {
|
||||
void f() {
|
||||
new <error descr="'ii' is abstract; cannot be instantiated">ii</error>();
|
||||
<error descr="'ii' is abstract; cannot be instantiated">new ii()</error>;
|
||||
|
||||
new <error descr="'c1' is abstract; cannot be instantiated">c1</error>();
|
||||
<error descr="'c1' is abstract; cannot be instantiated">new c1()</error>;
|
||||
|
||||
new <error descr="Class 'Anonymous class derived from c1' must either be declared abstract or implement abstract method 'f1(int)' in 'c1'">c1</error>() {
|
||||
public void f2() {}
|
||||
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// "Implement Methods" "true"
|
||||
class c {
|
||||
void foo() {
|
||||
new I<String>()<caret>
|
||||
}
|
||||
}
|
||||
interface I<T> {
|
||||
foo(T t);
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// "Implement Methods" "true"
|
||||
class c {
|
||||
void foo() {
|
||||
new Runnable()<caret>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.intellij.codeInsight;
|
||||
|
||||
import com.intellij.codeInsight.daemon.quickFix.LightQuickFixAvailabilityTestCase;
|
||||
|
||||
/**
|
||||
* User: anna
|
||||
* Date: 10/7/11
|
||||
*/
|
||||
public class ImplementAbstractFromNewTest extends LightQuickFixAvailabilityTestCase {
|
||||
public void test() throws Exception {
|
||||
doAllTests();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return "/codeInsight/daemonCodeAnalyzer/quickFix/implementAbstractFromNew";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user