From 607d4e4f7938b8f1fd6b11a48a9710c78bd47508 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Tue, 23 Dec 2014 19:29:02 +0100 Subject: [PATCH] make static: allow to delegate (IDEA-24060) --- .../changeSignature/JavaChangeInfoImpl.java | 2 +- .../JavaChangeSignatureUsageProcessor.java | 2 +- .../makeStatic/AbstractMakeStaticDialog.java | 7 ++- .../makeStatic/MakeMethodStaticProcessor.java | 48 +++++++++++++++++-- .../MakeParameterizedStaticDialog.java | 10 ++++ .../refactoring/makeStatic/Settings.java | 14 ++++++ .../afterFieldsAndDelegation.java | 18 +++++++ .../beforeFieldsAndDelegation.java | 13 +++++ .../refactoring/MakeMethodStaticTest.java | 22 +++++++-- 9 files changed, 125 insertions(+), 11 deletions(-) create mode 100644 java/java-tests/testData/refactoring/makeMethodStatic/afterFieldsAndDelegation.java create mode 100644 java/java-tests/testData/refactoring/makeMethodStatic/beforeFieldsAndDelegation.java diff --git a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeInfoImpl.java b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeInfoImpl.java index 2157b7040d16..e60f7fd3d974 100644 --- a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeInfoImpl.java +++ b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeInfoImpl.java @@ -35,7 +35,7 @@ import java.util.*; import static com.intellij.refactoring.changeSignature.ChangeSignatureUtil.deepTypeEqual; -class JavaChangeInfoImpl implements JavaChangeInfo { +public class JavaChangeInfoImpl implements JavaChangeInfo { private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.changeSignature.JavaChangeInfoImpl"); @PsiModifier.ModifierConstant diff --git a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureUsageProcessor.java b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureUsageProcessor.java index ab3cc1330039..3d72a85ea15d 100644 --- a/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureUsageProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/changeSignature/JavaChangeSignatureUsageProcessor.java @@ -636,7 +636,7 @@ public class JavaChangeSignatureUsageProcessor implements ChangeSignatureUsagePr !((JavaChangeInfoImpl)changeInfo).propagateParametersMethods.contains(method); } - private static void generateDelegate(JavaChangeInfo changeInfo) throws IncorrectOperationException { + public static void generateDelegate(JavaChangeInfo changeInfo) throws IncorrectOperationException { final PsiMethod delegate = (PsiMethod)changeInfo.getMethod().copy(); final PsiClass targetClass = changeInfo.getMethod().getContainingClass(); LOG.assertTrue(targetClass != null); diff --git a/java/java-impl/src/com/intellij/refactoring/makeStatic/AbstractMakeStaticDialog.java b/java/java-impl/src/com/intellij/refactoring/makeStatic/AbstractMakeStaticDialog.java index a990681da32e..153739f95d1d 100644 --- a/java/java-impl/src/com/intellij/refactoring/makeStatic/AbstractMakeStaticDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/makeStatic/AbstractMakeStaticDialog.java @@ -52,7 +52,8 @@ public abstract class AbstractMakeStaticDialog extends RefactoringDialog { final Settings settings = new Settings( isReplaceUsages(), isMakeClassParameter() ? getClassParameterName() : null, - getVariableData() + getVariableData(), + isGenerateDelegate() ); if (myMember instanceof PsiMethod) { invokeRefactoring(new MakeMethodStaticProcessor(getProject(), (PsiMethod)myMember, settings)); @@ -62,6 +63,10 @@ public abstract class AbstractMakeStaticDialog extends RefactoringDialog { } } + protected boolean isGenerateDelegate() { + return false; + } + protected abstract boolean validateData(); public abstract boolean isMakeClassParameter(); diff --git a/java/java-impl/src/com/intellij/refactoring/makeStatic/MakeMethodStaticProcessor.java b/java/java-impl/src/com/intellij/refactoring/makeStatic/MakeMethodStaticProcessor.java index 5f13be0fb7f9..d5b7b84ab161 100644 --- a/java/java-impl/src/com/intellij/refactoring/makeStatic/MakeMethodStaticProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/makeStatic/MakeMethodStaticProcessor.java @@ -16,6 +16,7 @@ package com.intellij.refactoring.makeStatic; import com.intellij.codeInsight.TestFrameworks; +import com.intellij.lang.Language; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; @@ -25,18 +26,21 @@ import com.intellij.psi.javadoc.PsiDocTag; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; +import com.intellij.refactoring.changeSignature.*; import com.intellij.refactoring.changeSignature.inCallers.JavaCallerChooser; +import com.intellij.refactoring.util.CanonicalTypes; import com.intellij.refactoring.util.RefactoringUtil; import com.intellij.refactoring.util.javadoc.MethodJavaDocHelper; import com.intellij.usageView.UsageInfo; import com.intellij.util.Consumer; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.VisibilityUtil; import com.intellij.util.containers.MultiMap; import com.intellij.util.ui.tree.TreeUtil; +import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; /** * @author dsl @@ -131,9 +135,44 @@ public class MakeMethodStaticProcessor extends MakeMethodOrClassStaticProcessor< PsiDocTag anchor = null; List addedTypes = new ArrayList(); + final PsiClass containingClass = myMember.getContainingClass(); + LOG.assertTrue(containingClass != null); + + if (mySettings.isDelegate()) { + List params = new ArrayList(); + PsiParameter[] parameters = myMember.getParameterList().getParameters(); + + for (int i = 0; i < parameters.length; i++) { + params.add(new ParameterInfoImpl(i)); + } + + if (mySettings.isMakeClassParameter()) { + params.add(new ParameterInfoImpl(-1, mySettings.getClassParameterName(), + factory.createType(containingClass, PsiSubstitutor.EMPTY), "this")); + } + + if (mySettings.isMakeFieldParameters()) { + for (Settings.FieldParameter parameter : mySettings.getParameterOrderList()) { + params.add(new ParameterInfoImpl(-1, mySettings.getClassParameterName(), parameter.type, parameter.field.getName())); + } + } + + final PsiType returnType = myMember.getReturnType(); + LOG.assertTrue(returnType != null); + JavaChangeSignatureUsageProcessor.generateDelegate(new JavaChangeInfoImpl(VisibilityUtil.getVisibilityModifier(myMember.getModifierList()), + myMember, + myMember.getName(), + CanonicalTypes.createTypeWrapper(returnType), + params.toArray(new ParameterInfoImpl[params.size()]), + new ThrownExceptionInfo[0], + false, + Collections.emptySet(), + Collections.emptySet())); + } + if (mySettings.isMakeClassParameter()) { // Add parameter for object - PsiType parameterType = factory.createType(myMember.getContainingClass(), PsiSubstitutor.EMPTY); + PsiType parameterType = factory.createType(containingClass, PsiSubstitutor.EMPTY); addedTypes.add(parameterType); final String classParameterName = mySettings.getClassParameterName(); @@ -310,6 +349,7 @@ public class MakeMethodStaticProcessor extends MakeMethodOrClassStaticProcessor< } protected void findExternalUsages(final ArrayList result) { + if (mySettings.isDelegate()) return; findExternalReferences(myMember, result); } diff --git a/java/java-impl/src/com/intellij/refactoring/makeStatic/MakeParameterizedStaticDialog.java b/java/java-impl/src/com/intellij/refactoring/makeStatic/MakeParameterizedStaticDialog.java index b08c8d33ca0f..f5187b44f3e5 100644 --- a/java/java-impl/src/com/intellij/refactoring/makeStatic/MakeParameterizedStaticDialog.java +++ b/java/java-impl/src/com/intellij/refactoring/makeStatic/MakeParameterizedStaticDialog.java @@ -55,6 +55,7 @@ public class MakeParameterizedStaticDialog extends AbstractMakeStaticDialog { private ParameterTablePanel myParameterPanel; private VariableData[] myVariableData; private final boolean myAnyNonFieldMembersUsed; + private JCheckBox myGenerateDelegateCb; public MakeParameterizedStaticDialog(Project project, @@ -212,12 +213,21 @@ public class MakeParameterizedStaticDialog extends AbstractMakeStaticDialog { myMakeFieldParameters.addActionListener(inputFieldValidator); + if (myMember instanceof PsiMethod) { + myGenerateDelegateCb = new JCheckBox(RefactoringBundle.message("delegation.panel.delegate.via.overloading.method")); + panel.add(myGenerateDelegateCb, gbConstraints); + } updateControls(); return panel; } + @Override + protected boolean isGenerateDelegate() { + return myGenerateDelegateCb != null && myGenerateDelegateCb.isSelected(); + } + protected boolean validateData() { int ret = Messages.YES; if (isMakeClassParameter()) { diff --git a/java/java-impl/src/com/intellij/refactoring/makeStatic/Settings.java b/java/java-impl/src/com/intellij/refactoring/makeStatic/Settings.java index c08de3870f0f..c153e2c4433c 100644 --- a/java/java-impl/src/com/intellij/refactoring/makeStatic/Settings.java +++ b/java/java-impl/src/com/intellij/refactoring/makeStatic/Settings.java @@ -40,6 +40,7 @@ public final class Settings { private final HashMap myFieldToNameMapping; private final ArrayList myFieldToNameList; private final boolean myReplaceUsages; + private final boolean myDelegate; public static final class FieldParameter { @@ -56,7 +57,15 @@ public final class Settings { public Settings(boolean replaceUsages, @Nullable String classParameterName, @Nullable VariableData[] variableDatum) { + this(replaceUsages, classParameterName, variableDatum, false); + } + + public Settings(boolean replaceUsages, + @Nullable String classParameterName, + @Nullable VariableData[] variableDatum, + boolean delegate) { myReplaceUsages = replaceUsages; + myDelegate = delegate; myMakeClassParameter = classParameterName != null; myClassParameterName = classParameterName; myMakeFieldParameters = variableDatum != null; @@ -94,6 +103,7 @@ public final class Settings { else { myFieldToNameMapping = null; } + myDelegate = false; } public boolean isReplaceUsages() { @@ -112,6 +122,10 @@ public final class Settings { return myMakeFieldParameters; } + public boolean isDelegate() { + return myDelegate; + } + @Nullable public String getNameForField(PsiField field) { if (myFieldToNameMapping != null) { diff --git a/java/java-tests/testData/refactoring/makeMethodStatic/afterFieldsAndDelegation.java b/java/java-tests/testData/refactoring/makeMethodStatic/afterFieldsAndDelegation.java new file mode 100644 index 000000000000..2624eef3ce7a --- /dev/null +++ b/java/java-tests/testData/refactoring/makeMethodStatic/afterFieldsAndDelegation.java @@ -0,0 +1,18 @@ +class C { + int i; + + private void foo() { + foo(i); + } + + private static void foo(int i) { + if (true) { + foo(i); + } + System.out.println(i); + } + + { + foo(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/makeMethodStatic/beforeFieldsAndDelegation.java b/java/java-tests/testData/refactoring/makeMethodStatic/beforeFieldsAndDelegation.java new file mode 100644 index 000000000000..d0ad4ac20296 --- /dev/null +++ b/java/java-tests/testData/refactoring/makeMethodStatic/beforeFieldsAndDelegation.java @@ -0,0 +1,13 @@ +class C { + int i; + private void foo() { + if (true) { + foo(); + } + System.out.println(i); + } + + { + foo(); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/refactoring/MakeMethodStaticTest.java b/java/java-tests/testSrc/com/intellij/refactoring/MakeMethodStaticTest.java index f5ae8121f45e..6427e2e05265 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/MakeMethodStaticTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/MakeMethodStaticTest.java @@ -185,9 +185,11 @@ public class MakeMethodStaticTest extends LightRefactoringTestCase { } public void testPreserveTypeParams() throws Exception { - configureByFile("/refactoring/makeMethodStatic/beforePreserveTypeParams.java"); - performWithFields(); - checkResultByFile("/refactoring/makeMethodStatic/afterPreserveTypeParams.java"); + doTestFields(false); + } + + public void testFieldsAndDelegation() throws Exception { + doTestFields(true); } public void testInnerStaticClassUsed() throws Exception { @@ -215,6 +217,14 @@ public class MakeMethodStaticTest extends LightRefactoringTestCase { checkResultByFile("/refactoring/makeMethodStatic/after" + getTestName(false) + ".java"); } + private void doTestFields(boolean delegate) throws Exception { + final String testName = getTestName(false); + configureByFile("/refactoring/makeMethodStatic/before" + testName + ".java"); + performWithFields(delegate); + checkResultByFile("/refactoring/makeMethodStatic/after" + testName + ".java"); + } + + private static void perform(boolean addClassParameter) { PsiElement element = TargetElementUtilBase.findTargetElement(myEditor, TargetElementUtilBase.ELEMENT_NAME_ACCEPTED); assertTrue(element instanceof PsiMethod); @@ -227,6 +237,10 @@ public class MakeMethodStaticTest extends LightRefactoringTestCase { } private static void performWithFields() { + performWithFields(false); + } + + private static void performWithFields(boolean delegate) { PsiElement element = TargetElementUtilBase.findTargetElement(myEditor, TargetElementUtilBase.ELEMENT_NAME_ACCEPTED); assertTrue(element instanceof PsiMethod); PsiMethod method = (PsiMethod) element; @@ -238,6 +252,6 @@ public class MakeMethodStaticTest extends LightRefactoringTestCase { method, new Settings(true, addClassParameter ? "anObject" : null, parametersForFields.toArray( - new VariableData[parametersForFields.size()]))).run(); + new VariableData[parametersForFields.size()]), delegate)).run(); } }