From 6ad85ec8553ec43f6b7b701645be46a66f4cff4a Mon Sep 17 00:00:00 2001 From: Anton Makeev Date: Mon, 21 Sep 2009 18:29:28 +0400 Subject: [PATCH] Quick Fix: Create Abstract Method from Usage --- .../impl/analysis/HighlightMethodUtil.java | 2 + .../CreateAbstractMethodFromUsageFix.java | 42 +++++++++++++++++++ .../impl/quickfix/CreateFromUsageBaseFix.java | 10 +++-- .../quickfix/CreateMethodFromUsageFix.java | 40 ++++++++++++++---- .../src/com/intellij/psi/util/PsiUtil.java | 5 +++ .../src/messages/QuickFixBundle.properties | 1 + 6 files changed, 90 insertions(+), 10 deletions(-) create mode 100644 java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateAbstractMethodFromUsageFix.java diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java index 48fc8f4e5d4d..2bf7de59a067 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightMethodUtil.java @@ -350,6 +350,7 @@ public class HighlightMethodUtil { else { TextRange range = getFixRange(methodCall); QuickFixAction.registerQuickFixAction(highlightInfo, range, new CreateMethodFromUsageFix(methodCall), null); + QuickFixAction.registerQuickFixAction(highlightInfo, range, new CreateAbstractMethodFromUsageFix(methodCall), null); QuickFixAction.registerQuickFixAction(highlightInfo, range, new CreatePropertyFromUsageFix(methodCall), null); } } @@ -461,6 +462,7 @@ public class HighlightMethodUtil { PsiExpressionList list, PsiResolveHelper resolveHelper) { TextRange fixRange = getFixRange(methodCall); QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, new CreateMethodFromUsageFix(methodCall), null); + QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, new CreateAbstractMethodFromUsageFix(methodCall), null); QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, new CreateConstructorFromSuperFix(methodCall), null); QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, new CreateConstructorFromThisFix(methodCall), null); QuickFixAction.registerQuickFixAction(highlightInfo, fixRange, new CreatePropertyFromUsageFix(methodCall), null); diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateAbstractMethodFromUsageFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateAbstractMethodFromUsageFix.java new file mode 100644 index 000000000000..2835aeb83811 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateAbstractMethodFromUsageFix.java @@ -0,0 +1,42 @@ +package com.intellij.codeInsight.daemon.impl.quickfix; + +import com.intellij.codeInsight.daemon.QuickFixBundle; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiUtil; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +public class CreateAbstractMethodFromUsageFix extends CreateMethodFromUsageFix { + public CreateAbstractMethodFromUsageFix(PsiMethodCallExpression methodCall) { + super(methodCall); + } + + @Override + protected String getDisplayString(String name) { + return QuickFixBundle.message("create.abstract.method.from.usage.text", name); + } + + @NotNull + @Override + protected List getTargetClasses(PsiElement element) { + List result = new ArrayList(); + PsiReferenceExpression expr = getMethodCall().getMethodExpression(); + for (PsiClass each : super.getTargetClasses(element)) { + if (PsiUtil.isAbstractClass(each) && !each.isInterface() && !shouldCreateStaticMember(expr, each)) result.add(each); + } + return result; + } + + @Override + protected String getVisibility(PsiClass parentClass, PsiClass targetClass) { + String result = super.getVisibility(parentClass, targetClass); + return PsiModifier.PUBLIC.equals(result) ? result : PsiModifier.PROTECTED; + } + + @Override + protected boolean shouldBeAbstract(PsiClass targetClass) { + return true; + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageBaseFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageBaseFix.java index bed1f071f493..7d5942c812fd 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageBaseFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateFromUsageBaseFix.java @@ -20,6 +20,7 @@ import com.intellij.openapi.ui.popup.PopupChooserBuilder; import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.refactoring.util.RefactoringUtil; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -134,16 +135,19 @@ public abstract class CreateFromUsageBaseFix extends BaseIntentionAction { return FileEditorManager.getInstance(project).openTextEditor(descriptor, true); } - protected static void setupVisibility(PsiClass parentClass, PsiClass targetClass, PsiModifierList list) throws IncorrectOperationException { + protected void setupVisibility(PsiClass parentClass, PsiClass targetClass, PsiModifierList list) throws IncorrectOperationException { if (targetClass.isInterface()) { list.deleteChildRange(list.getFirstChild(), list.getLastChild()); return; } + RefactoringUtil.setVisibility(list, getVisibility(parentClass, targetClass)); + } + protected String getVisibility(PsiClass parentClass, PsiClass targetClass) { if (parentClass != null && (parentClass.equals(targetClass) || PsiTreeUtil.isAncestor(targetClass, parentClass, true))) { - list.setModifierProperty(PsiModifier.PRIVATE, true); + return PsiModifier.PRIVATE; } else { - list.setModifierProperty(PsiModifier.PUBLIC, true); + return PsiModifier.PUBLIC; } } diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodFromUsageFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodFromUsageFix.java index 0a328847ccec..9b2964477820 100644 --- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodFromUsageFix.java +++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/CreateMethodFromUsageFix.java @@ -50,10 +50,14 @@ public class CreateMethodFromUsageFix extends CreateFromUsageBaseFix { if (name == null || !JavaPsiFacade.getInstance(ref.getProject()).getNameHelper().isIdentifier(name)) return false; if (hasErrorsInArgumentList(call)) return false; - setText(QuickFixBundle.message("create.method.from.usage.text", name)); + setText(getDisplayString(name)); return true; } + protected String getDisplayString(String name) { + return QuickFixBundle.message("create.method.from.usage.text", name); + } + private static boolean isMethodSignatureExists(PsiMethodCallExpression call, PsiClass target) { String name = call.getMethodExpression().getReferenceName(); PsiExpressionList list = call.getArgumentList(); @@ -142,20 +146,24 @@ public class CreateMethodFromUsageFix extends CreateFromUsageBaseFix { PsiCodeBlock body = method.getBody(); assert body != null; - if (targetClass.isInterface()) { + if (shouldBeAbstract(targetClass)) { body.delete(); + if (!targetClass.isInterface()) { + method.getModifierList().setModifierProperty(PsiModifier.ABSTRACT, true); + } } setupVisibility(parentClass, targetClass, method.getModifierList()); - if (shouldCreateStaticMember(expression.getMethodExpression(), targetClass) && !targetClass.isInterface()) { + if (shouldCreateStaticMember(expression.getMethodExpression(), targetClass) && !shouldBeAbstract(targetClass)) { PsiUtil.setModifierProperty(method, PsiModifier.STATIC, true); } final PsiElement context = PsiTreeUtil.getParentOfType(expression, PsiClass.class, PsiMethod.class); PsiExpression[] arguments = expression.getArgumentList().getExpressions(); - doCreate(targetClass, method, ContainerUtil.map2List(arguments, new Function>() { + doCreate(targetClass, method, shouldBeAbstract(targetClass), + ContainerUtil.map2List(arguments, new Function>() { public Pair fun(PsiExpression psiExpression) { return Pair.create(psiExpression, null); } @@ -169,6 +177,16 @@ public class CreateMethodFromUsageFix extends CreateFromUsageBaseFix { public static void doCreate(PsiClass targetClass, PsiMethod method, List> arguments, PsiSubstitutor substitutor, ExpectedTypeInfo[] expectedTypes, @Nullable PsiElement context) { + doCreate(targetClass, method, shouldBeAbstractImpl(targetClass), arguments, substitutor, expectedTypes, context); + } + + private static void doCreate(PsiClass targetClass, + PsiMethod method, + boolean shouldBeAbstract, + List> arguments, + PsiSubstitutor substitutor, + ExpectedTypeInfo[] expectedTypes, + @Nullable PsiElement context) { method = CodeInsightUtilBase.forcePsiPostprocessAndRestoreElement(method); @@ -185,7 +203,7 @@ public class CreateMethodFromUsageFix extends CreateFromUsageBaseFix { new GuessTypeParameters(JavaPsiFacade.getInstance(project).getElementFactory()) .setupTypeElement(method.getReturnTypeElement(), expectedTypes, substitutor, builder, context, targetClass); PsiCodeBlock body = method.getBody(); - builder.setEndVariableAfter(targetClass.isInterface() || body == null ? method : body.getLBrace()); + builder.setEndVariableAfter(shouldBeAbstract || body == null ? method : body.getLBrace()); method = CodeInsightUtilBase.forcePsiPostprocessAndRestoreElement(method); if (method == null) return; @@ -196,7 +214,7 @@ public class CreateMethodFromUsageFix extends CreateFromUsageBaseFix { newEditor.getCaretModel().moveToOffset(rangeMarker.getStartOffset()); newEditor.getDocument().deleteString(rangeMarker.getStartOffset(), rangeMarker.getEndOffset()); - if (!targetClass.isInterface()) { + if (!shouldBeAbstract) { startTemplate(newEditor, template, project, new TemplateEditingAdapter() { public void templateFinished(Template template) { ApplicationManager.getApplication().runWriteAction(new Runnable() { @@ -225,6 +243,14 @@ public class CreateMethodFromUsageFix extends CreateFromUsageBaseFix { } } + protected boolean shouldBeAbstract(PsiClass targetClass) { + return shouldBeAbstractImpl(targetClass); + } + + private static boolean shouldBeAbstractImpl(PsiClass targetClass) { + return targetClass.isInterface(); + } + protected boolean isValidElement(PsiElement element) { PsiMethodCallExpression callExpression = (PsiMethodCallExpression) element; PsiReferenceExpression referenceExpression = callExpression.getMethodExpression(); @@ -238,7 +264,7 @@ public class CreateMethodFromUsageFix extends CreateFromUsageBaseFix { } @Nullable - private PsiMethodCallExpression getMethodCall() { + protected PsiMethodCallExpression getMethodCall() { return (PsiMethodCallExpression)myMethodCall.getElement(); } } diff --git a/java/openapi/src/com/intellij/psi/util/PsiUtil.java b/java/openapi/src/com/intellij/psi/util/PsiUtil.java index 6c56f4ab139a..6a38d7fd3db9 100644 --- a/java/openapi/src/com/intellij/psi/util/PsiUtil.java +++ b/java/openapi/src/com/intellij/psi/util/PsiUtil.java @@ -220,6 +220,11 @@ public final class PsiUtil extends PsiUtilBase { return parent instanceof PsiDeclarationStatement && parent.getParent() instanceof PsiCodeBlock; } + public static boolean isAbstractClass(PsiClass clazz) { + PsiModifierList modifierList = clazz.getModifierList(); + return modifierList != null && modifierList.hasModifierProperty(PsiModifier.ABSTRACT); + } + /** * @return codeblock topmost codeblock where variable makes sense */ diff --git a/resources-en/src/messages/QuickFixBundle.properties b/resources-en/src/messages/QuickFixBundle.properties index ac90cd7caa52..82f15f41e7d6 100644 --- a/resources-en/src/messages/QuickFixBundle.properties +++ b/resources-en/src/messages/QuickFixBundle.properties @@ -84,6 +84,7 @@ create.local.from.instanceof.usage.family=Create Local Var from instanceof Usage create.local.from.instanceof.usage.text=Insert ''({0}){1}'' declaration create.method.from.usage.family=Create Method from Usage create.method.from.usage.text=Create Method ''{0}'' +create.abstract.method.from.usage.text=Create Abstract Method ''{0}'' create.parameter.from.usage.family=Create Parameter from Usage create.parameter.from.usage.text=Create Parameter ''{0}'' create.property.from.usage.family=Create Property From Usage