merge extract closure into introduce parameter

This commit is contained in:
Maxim.Medvedev
2012-02-09 11:41:22 +04:00
parent 0af864e88c
commit 040cd95ebe
31 changed files with 524 additions and 703 deletions
-9
View File
@@ -1056,10 +1056,6 @@
class="org.jetbrains.plugins.groovy.actions.DumpGroovyStubsAction"
text="dump groovy stubs"
description="" internal="true"/>
<action id="Groovy.Extract.Closure" class="org.jetbrains.plugins.groovy.refactoring.extract.closure.ExtractClosureAction"
text="Closure...">
<keyboard-shortcut keymap="$default" first-keystroke="ctrl alt shift M"/>
</action>
<add-to-group group-id="Internal"/>
</group>
@@ -1105,11 +1101,6 @@
<add-to-group group-id="ToolsMenu" anchor="last"/>
</action>
<!--<action id="Groovy.Extract.Closure" class="org.jetbrains.plugins.groovy.refactoring.extract.closure.ExtractClosureAction" text="Closure...">
<add-to-group group-id="IntroduceActionsGroup" anchor="after" relative-to-action="ExtractMethod"/>
<keyboard-shortcut keymap="$default" first-keystroke="ctrl alt shift M"/>
</action>-->
<group id="Mvc.Actions" popup="true" class="org.jetbrains.plugins.groovy.mvc.MvcActionGroup">
<action id="Mvc.Upgrade"
class="org.jetbrains.plugins.groovy.mvc.MvcUpgradeAction"
@@ -50,4 +50,6 @@ public interface ExtractInfoHelper {
boolean hasReturnValue();
String getName();
PsiElement getContext();
}
@@ -30,11 +30,10 @@ import java.util.Map;
* @author Max Medvedev
*/
public abstract class ExtractInfoHelperBase implements ExtractInfoHelper {
protected final InitialInfo myInitialInfo;
protected final ExtractInfoHelper myInitialInfo;
protected final Map<String, ParameterInfo> myInputNamesMap;
public ExtractInfoHelperBase(
InitialInfo initialInfo) {
public ExtractInfoHelperBase(ExtractInfoHelper initialInfo) {
myInitialInfo = initialInfo;
final ParameterInfo[] infos = initialInfo.getParameterInfos();
@@ -109,4 +108,9 @@ public abstract class ExtractInfoHelperBase implements ExtractInfoHelper {
public boolean hasReturnValue() {
return myInitialInfo.hasReturnValue();
}
@Override
public PsiElement getContext() {
return myInitialInfo.getContext();
}
}
@@ -24,6 +24,8 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.HashSet;
import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils;
@@ -61,15 +63,21 @@ import static org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringUtil.*;
public class GroovyExtractChooser {
private static final Logger LOG = Logger.getInstance(GroovyExtractChooser.class);
public static InitialInfo invoke(Project project, Editor editor, PsiFile file, int start, int end) throws GrRefactoringError {
public static InitialInfo invoke(Project project, Editor editor, PsiFile file, int start, int end, boolean forceStatements) throws GrRefactoringError {
PsiDocumentManager.getInstance(project).commitAllDocuments();
if (!(file instanceof GroovyFileBase)) {
throw new GrRefactoringError(GroovyRefactoringBundle.message("only.in.groovy.files"));
}
if (!CommonRefactoringUtil.checkReadOnlyStatus(project, file)) {
throw new GrRefactoringError(RefactoringBundle.message("readonly.occurences.found"));
}
SelectionModel selectionModel = editor.getSelectionModel();
PsiDocumentManager.getInstance(project).commitAllDocuments();
PsiElement[] elements = getElementsInOffset(file, start, end);
PsiElement[] elements = getElementsInOffset(file, start, end, forceStatements);
if (elements.length == 1 && elements[0] instanceof GrExpression) {
selectionModel.setSelection(start, elements[0].getTextRange().getEndOffset());
}
@@ -166,26 +174,25 @@ public class GroovyExtractChooser {
ArrayList<GrStatement> statementList = new ArrayList<GrStatement>();
for (PsiElement element : elements) {
if (element instanceof GrStatement) {
statementList.add(((GrStatement) element));
statementList.add(((GrStatement)element));
}
}
return statementList.toArray(new GrStatement[statementList.size()]);
}
private static PsiElement[] getElementsInOffset(PsiFile file, int startOffset, int endOffset) {
PsiElement[] elements;
private static PsiElement[] getElementsInOffset(PsiFile file, int startOffset, int endOffset, boolean forceStatements) {
GrExpression expr = findElementInRange(file, startOffset, endOffset, GrExpression.class);
if (!forceStatements && expr != null) return new PsiElement[]{expr};
if (expr != null) {
PsiElement parent = expr.getParent();
if (expr.getParent() instanceof GrMethodCallExpression || parent instanceof GrIndexProperty) {
expr = ((GrExpression) expr.getParent());
}
elements = new PsiElement[]{expr};
} else {
elements = findStatementsInRange(file, startOffset, endOffset, true);
if (expr == null) {
return findStatementsInRange(file, startOffset, endOffset, true);
}
return elements;
PsiElement parent = expr.getParent();
if (expr.getParent() instanceof GrMethodCallExpression || parent instanceof GrIndexProperty) {
expr = ((GrExpression)expr.getParent());
}
return new PsiElement[]{expr};
}
private static boolean isReturnStatement(GrStatement statement, Collection<GrStatement> returnStatements) {
@@ -193,7 +200,6 @@ public class GroovyExtractChooser {
if (statement instanceof GrIfStatement) {
boolean checked = GroovyInlineMethodUtil.checkTailIfStatement(((GrIfStatement)statement), returnStatements);
return checked & returnStatements.size() == 0;
}
if (statement instanceof GrExpression) {
return returnStatements.contains(statement);
@@ -90,7 +90,7 @@ public class InitialInfo implements ExtractInfoHelper {
outputType = outputInfos[0].getType();
}
else {
outputType = JavaPsiFacade.getElementFactory(myProject).createTypeFromText(CommonClassNames.JAVA_UTIL_LIST, myStatements[0]);
outputType = JavaPsiFacade.getElementFactory(myProject).createTypeFromText(CommonClassNames.JAVA_UTIL_LIST, getContext());
}
}
else if (ExtractUtil.isSingleExpression(statements)) {
@@ -113,7 +113,7 @@ public class InitialInfo implements ExtractInfoHelper {
types.add(((GrExpression)statement).getType());
}
}
outputType = TypesUtil.getLeastUpperBoundNullable(types, statements[0].getManager());
outputType = TypesUtil.getLeastUpperBoundNullable(types, getContext().getManager());
}
return outputType;
@@ -174,4 +174,9 @@ public class InitialInfo implements ExtractInfoHelper {
public String getName() {
throw new UnsupportedOperationException();
}
@Override
public PsiElement getContext() {
return myStatements[0];
}
}
@@ -19,10 +19,8 @@ import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Splitter;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.refactoring.IntroduceParameterRefactoring;
import com.intellij.refactoring.JavaRefactoringSettings;
import com.intellij.ui.EditorTextField;
import com.intellij.ui.IdeBorderFactory;
@@ -34,14 +32,14 @@ import gnu.trove.TObjectIntHashMap;
import gnu.trove.TObjectIntProcedure;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.GroovyFileType;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrParametersOwner;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter;
import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringBundle;
import org.jetbrains.plugins.groovy.refactoring.extract.ExtractUtil;
import org.jetbrains.plugins.groovy.refactoring.extract.InitialInfo;
import org.jetbrains.plugins.groovy.refactoring.extract.ParameterInfo;
import org.jetbrains.plugins.groovy.refactoring.extract.ParameterTablePanel;
import org.jetbrains.plugins.groovy.refactoring.introduce.parameter.GrIntroduceParameterSettings;
import org.jetbrains.plugins.groovy.refactoring.introduce.parameter.GroovyIntroduceParameterUtil;
import org.jetbrains.plugins.groovy.refactoring.introduce.parameter.IntroduceParameterInfo;
import org.jetbrains.plugins.groovy.refactoring.ui.GrMethodSignatureComponent;
import javax.swing.*;
@@ -56,18 +54,18 @@ public class ExtractClosureDialog extends DialogWrapper {
private final GrMethodSignatureComponent mySignature;
private final EditorTextField myNameField;
private final ExtractClosureHelper myHelper;
private final IntroduceParameterInfo myInfo;
private final JBCheckBox myFinalCB;
private final JBCheckBox myGenerateDelegateCB;
TObjectIntHashMap<JBCheckBox> toRemoveCBs;
public ExtractClosureDialog(InitialInfo initialInfo, GrParametersOwner owner, PsiElement toSearchFor) {
public ExtractClosureDialog(IntroduceParameterInfo initialInfo) {
super(initialInfo.getProject());
myHelper = new ExtractClosureHelper(initialInfo, owner, toSearchFor, "", false);
myInfo = initialInfo;
setTitle(ExtractClosureHandler.EXTRACT_CLOSURE);
setTitle("Extract closure");
myTable = new ParameterTablePanel() {
@Override
@@ -93,7 +91,7 @@ public class ExtractClosureDialog extends DialogWrapper {
myGenerateDelegateCB = new JBCheckBox(UIUtil.replaceMnemonicAmpersand("De&legate via overloading method"));
myGenerateDelegateCB.setFocusable(false);
TObjectIntHashMap<GrParameter> parametersToRemove = findParametersToRemove(myHelper);
TObjectIntHashMap<GrParameter> parametersToRemove = GroovyIntroduceParameterUtil.findParametersToRemove(myInfo);
toRemoveCBs = new TObjectIntHashMap<JBCheckBox>(parametersToRemove.size());
for (Object p : parametersToRemove.keys()) {
JBCheckBox cb = new JBCheckBox(GroovyRefactoringBundle.message("remove.parameter.0.no.longer.used", ((GrParameter)p).getName()));
@@ -118,7 +116,7 @@ public class ExtractClosureDialog extends DialogWrapper {
if (!checkbox.isSelected()) return true;
final GrParameter param = myHelper.getOwner().getParameters()[index];
final GrParameter param = myInfo.getToReplaceIn().getParameters()[index];
final ParameterInfo pinfo = findParamByOldName(param.getName());
if (pinfo == null || !pinfo.passAsParameter()) return true;
@@ -133,7 +131,7 @@ public class ExtractClosureDialog extends DialogWrapper {
@Nullable
private ParameterInfo findParamByOldName(String name) {
for (ParameterInfo info : myHelper.getParameterInfos()) {
for (ParameterInfo info : myInfo.getParameterInfos()) {
if (name.equals(info.getOldName())) return info;
}
return null;
@@ -142,7 +140,7 @@ public class ExtractClosureDialog extends DialogWrapper {
private void updateSignature() {
StringBuilder b = new StringBuilder();
b.append("{ ");
String[] params = ExtractUtil.getParameterString(myHelper, false);
String[] params = ExtractUtil.getParameterString(myInfo, false);
for (int i = 0; i < params.length; i++) {
if (i > 0) {
b.append(" ");
@@ -163,16 +161,16 @@ public class ExtractClosureDialog extends DialogWrapper {
protected void init() {
super.init();
myTable.init(myHelper);
myTable.init(myInfo);
final JavaRefactoringSettings refactoringSettings = JavaRefactoringSettings.getInstance();
final Boolean settingsFinals = refactoringSettings.INTRODUCE_PARAMETER_CREATE_FINALS;
myFinalCB.setSelected(settingsFinals == null ?
CodeStyleSettingsManager.getSettings(myHelper.getProject()).GENERATE_FINAL_PARAMETERS :
CodeStyleSettingsManager.getSettings(myInfo.getProject()).GENERATE_FINAL_PARAMETERS :
settingsFinals.booleanValue());
myGenerateDelegateCB.setSelected(false);
final GrParameter[] parameters = myHelper.getOwner().getParameters();
final GrParameter[] parameters = myInfo.getToReplaceIn().getParameters();
toRemoveCBs.forEachEntry(new TObjectIntProcedure<JBCheckBox>() {
@Override
public boolean execute(JBCheckBox checkbox, int index) {
@@ -234,10 +232,10 @@ public class ExtractClosureDialog extends DialogWrapper {
final JavaRefactoringSettings settings = JavaRefactoringSettings.getInstance();
settings.INTRODUCE_PARAMETER_CREATE_FINALS = Boolean.valueOf(myFinalCB.isSelected());
myHelper.setName(myNameField.getText());
myHelper.setDeclareFinal(myFinalCB.isSelected());
myHelper.setGenerateDelegate(myGenerateDelegateCB.isSelected());
super.doOKAction();
}
public GrIntroduceParameterSettings getHelper() {
TIntArrayList list = new TIntArrayList();
for (Object cb : toRemoveCBs.keys()) {
final JBCheckBox checkbox = (JBCheckBox)cb;
@@ -245,41 +243,13 @@ public class ExtractClosureDialog extends DialogWrapper {
list.add(toRemoveCBs.get(checkbox));
}
}
myHelper.setToRemove(list);
super.doOKAction();
}
public ExtractClosureHelper getHelper() {
return myHelper;
}
private static TObjectIntHashMap<GrParameter> findParametersToRemove(ExtractClosureHelper helper) {
final TObjectIntHashMap<GrParameter> result = new TObjectIntHashMap<GrParameter>();
final GrStatement[] statements = helper.getStatements();
final int start = statements[0].getTextRange().getStartOffset();
final int end = statements[statements.length - 1].getTextRange().getEndOffset();
GrParameter[] parameters = helper.getOwner().getParameters();
for (int i = 0; i < parameters.length; i++) {
GrParameter parameter = parameters[i];
if (shouldRemove(parameter, start, end)) {
result.put(parameter, i);
}
}
return result;
}
private static boolean shouldRemove(GrParameter parameter, int start, int end) {
for (PsiReference reference : ReferencesSearch.search(parameter)) {
final PsiElement element = reference.getElement();
if (element == null) continue;
final int offset = element.getTextRange().getStartOffset();
if (offset < start || end <= offset) {
return false;
}
}
return true;
return new ExtractClosureHelperImpl(myInfo,
myNameField.getText(),
myFinalCB.isSelected(),
list,
myGenerateDelegateCB.isSelected(),
IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_NONE
);
}
}
@@ -27,6 +27,7 @@ import org.jetbrains.plugins.groovy.GroovyFileType;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCall;
import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringUtil;
import org.jetbrains.plugins.groovy.refactoring.introduce.parameter.GrIntroduceParameterSettings;
import java.util.ArrayList;
import java.util.List;
@@ -35,7 +36,7 @@ import java.util.List;
* @author Max Medvedev
*/
public class ExtractClosureFromClosureProcessor extends ExtractClosureProcessorBase {
public ExtractClosureFromClosureProcessor(@NotNull ExtractClosureHelper helper) {
public ExtractClosureFromClosureProcessor(@NotNull GrIntroduceParameterSettings helper) {
super(helper);
}
@@ -16,7 +16,6 @@
package org.jetbrains.plugins.groovy.refactoring.extract.closure;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.*;
@@ -51,6 +50,7 @@ import org.jetbrains.plugins.groovy.refactoring.extract.ExtractUtil;
import org.jetbrains.plugins.groovy.refactoring.introduce.parameter.AnySupers;
import org.jetbrains.plugins.groovy.refactoring.introduce.parameter.FieldConflictsResolver;
import org.jetbrains.plugins.groovy.refactoring.introduce.parameter.GrExpressionWrapper;
import org.jetbrains.plugins.groovy.refactoring.introduce.parameter.GrIntroduceParameterSettings;
import java.util.ArrayList;
import java.util.Collection;
@@ -66,14 +66,12 @@ import static org.jetbrains.plugins.groovy.refactoring.introduce.parameter.Groov
public class ExtractClosureFromMethodProcessor extends ExtractClosureProcessorBase {
private final GrMethod myMethod;
private Editor myEditor;
private final GrStatementOwner myDeclarationOwner;
public ExtractClosureFromMethodProcessor(@NotNull ExtractClosureHelper helper, Editor editor) {
public ExtractClosureFromMethodProcessor(@NotNull GrIntroduceParameterSettings helper) {
super(helper);
myEditor = editor;
myDeclarationOwner = GroovyRefactoringUtil.getDeclarationOwner(helper.getStatements()[0]);
myMethod = (GrMethod)myHelper.getOwner();
myMethod = (GrMethod)myHelper.getToReplaceIn();
}
@Override
@@ -211,10 +209,11 @@ public class ExtractClosureFromMethodProcessor extends ExtractClosureProcessorBa
}
final GrStatement newStatement = ExtractUtil.replaceStatement(myDeclarationOwner, myHelper);
/*
if (myEditor != null) {
PsiDocumentManager.getInstance(myProject).commitDocument(myEditor.getDocument());
myEditor.getCaretModel().moveToOffset(ExtractUtil.getCaretOffset(newStatement));
}
}*/
fieldConflictsResolver.fix();
}
@@ -1,166 +0,0 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.refactoring.extract.closure;
import com.intellij.ide.util.SuperMethodWarningUtil;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.SelectionModel;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.util.Pass;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.refactoring.IntroduceTargetChooser;
import com.intellij.refactoring.RefactoringActionHandler;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.intellij.util.Function;
import com.intellij.util.PairFunction;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrParametersOwner;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
import org.jetbrains.plugins.groovy.refactoring.GrRefactoringError;
import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringBundle;
import org.jetbrains.plugins.groovy.refactoring.HelpID;
import org.jetbrains.plugins.groovy.refactoring.extract.GroovyExtractChooser;
import org.jetbrains.plugins.groovy.refactoring.extract.InitialInfo;
import org.jetbrains.plugins.groovy.refactoring.introduce.GrIntroduceHandlerBase;
import org.jetbrains.plugins.groovy.refactoring.ui.MethodOrClosureScopeChooser;
import java.util.ArrayList;
import java.util.List;
/**
* @author Max Medvedev
*/
public class ExtractClosureHandler implements RefactoringActionHandler, MethodOrClosureScopeChooser.JBPopupOwner {
public static final String EXTRACT_CLOSURE = "Extract Closure";
private JBPopup myPopup;
@Override
public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file, DataContext dataContext) {
final SelectionModel selectionModel = editor.getSelectionModel();
if (!selectionModel.hasSelection()) {
final int offset = editor.getCaretModel().getOffset();
final List<GrExpression> expressions = GrIntroduceHandlerBase.collectExpressions(file, editor, offset);
if (expressions.size() == 1) {
final TextRange textRange = expressions.get(0).getTextRange();
selectionModel.setSelection(textRange.getStartOffset(), textRange.getEndOffset());
}
else {
final Pass<GrExpression> callback = new Pass<GrExpression>() {
public void pass(final GrExpression selectedValue) {
invoke(project, editor, file, selectedValue.getTextRange().getStartOffset(), selectedValue.getTextRange().getEndOffset());
}
};
final Function<GrExpression, String> renderer = new Function<GrExpression, String>() {
@Override
public String fun(GrExpression grExpression) {
return grExpression.getText();
}
};
IntroduceTargetChooser.showChooser(editor, expressions, callback, renderer);
return;
}
}
invoke(project, editor, file, selectionModel.getSelectionStart(), selectionModel.getSelectionEnd());
}
void invoke(Project project, Editor editor, PsiFile file, int start, int end) {
try {
final InitialInfo initialInfo = GroovyExtractChooser.invoke(project, editor, file, start, end);
performRefactoring(initialInfo, editor);
}
catch (GrRefactoringError e) {
CommonRefactoringUtil.showErrorHint(project, editor, e.getMessage(), EXTRACT_CLOSURE, HelpID.GROOVY_EXTRACT_CLOSURE);
}
}
@Nullable
protected ExtractClosureHelper getSettings(@NotNull InitialInfo initialInfo, GrParametersOwner owner, PsiElement toSearchFor) {
final ExtractClosureDialog dialog = new ExtractClosureDialog(initialInfo, owner, toSearchFor);
dialog.show();
if (!dialog.isOK()) return null;
return dialog.getHelper();
}
private void findScope(@NotNull PsiElement place,
@NotNull final Editor editor,
@NotNull PairFunction<GrParametersOwner, PsiElement, Object> callback) {
final List<GrParametersOwner> scopes = new ArrayList<GrParametersOwner>();
while (true) {
final GrParametersOwner parent = PsiTreeUtil.getParentOfType(place, GrMethod.class/*, GrClosableBlock.class*/); //todo implement extract closure from closure
if (parent == null) break;
scopes.add(parent);
place = parent;
}
if (scopes.size() == 0) {
throw new GrRefactoringError(GroovyRefactoringBundle.message("there.is.no.method.or.closure"));
}
else if (scopes.size() == 1) {
final GrParametersOwner owner = scopes.get(0);
if (owner instanceof GrMethod) {
PsiMethod newMethod = SuperMethodWarningUtil.checkSuperMethod((PsiMethod)owner, RefactoringBundle.message("to.refactor"));
if (newMethod == null) return;
callback.fun(owner, newMethod);
}
else {
callback.fun(owner, MethodOrClosureScopeChooser.findVariableToUse(owner));
}
}
else {
myPopup = MethodOrClosureScopeChooser.create(scopes, editor, this, callback);
myPopup.showInBestPositionFor(editor);
}
}
public void performRefactoring(@NotNull final InitialInfo info, final Editor editor) {
findScope(info.getStatements()[0], editor, new PairFunction<GrParametersOwner, PsiElement, Object>() {
@Override
public Object fun(GrParametersOwner owner, PsiElement toSearchFor) {
final ExtractClosureHelper helper = getSettings(info, owner, toSearchFor);
if (helper == null) return null;
if (helper.getOwner() instanceof GrMethod) {
new ExtractClosureFromMethodProcessor(helper, editor).run();
}
return null;
}
});
}
@Override
public void invoke(@NotNull Project project, @NotNull PsiElement[] elements, DataContext dataContext) {
//do nothing
}
@Override
public JBPopup get() {
return myPopup;
}
}
@@ -20,35 +20,44 @@ import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiType;
import gnu.trove.TIntArrayList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrParametersOwner;
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames;
import org.jetbrains.plugins.groovy.refactoring.extract.ExtractInfoHelper;
import org.jetbrains.plugins.groovy.refactoring.extract.ExtractInfoHelperBase;
import org.jetbrains.plugins.groovy.refactoring.extract.InitialInfo;
import org.jetbrains.plugins.groovy.refactoring.introduce.parameter.GrIntroduceParameterSettings;
import org.jetbrains.plugins.groovy.refactoring.introduce.parameter.IntroduceParameterInfo;
/**
* @author Max Medvedev
*/
public class ExtractClosureHelper extends ExtractInfoHelperBase implements ExtractInfoHelper, GrIntroduceParameterSettings {
public class ExtractClosureHelperImpl extends ExtractInfoHelperBase implements GrIntroduceParameterSettings {
private final GrParametersOwner myOwner;
private final PsiElement myToSearchFor;
private String myName;
private boolean myFinal;
private TIntArrayList toRemove;
private boolean myGenerateDelegate;
private final String myName;
private final boolean myFinal;
private final TIntArrayList myToRemove;
private final boolean myGenerateDelegate;
private final int myReplaceFieldsWithGetters;
public ExtractClosureHelper(InitialInfo info, GrParametersOwner owner, PsiElement toSearchFor, String name, boolean declareFinal) {
public ExtractClosureHelperImpl(IntroduceParameterInfo info,
String name,
boolean declareFinal,
TIntArrayList toRemove,
boolean generateDelegate,
int replaceFieldsWithGetters) {
super(info);
myOwner = owner;
myToSearchFor = toSearchFor;
myOwner = info.getToReplaceIn();
myToSearchFor = info.getToSearchFor();
myName = name;
myFinal = declareFinal;
myToRemove = toRemove;
myGenerateDelegate = generateDelegate;
myReplaceFieldsWithGetters = replaceFieldsWithGetters;
}
public GrParametersOwner getOwner() {
@NotNull
public GrParametersOwner getToReplaceIn() {
return myOwner;
}
@@ -64,26 +73,14 @@ public class ExtractClosureHelper extends ExtractInfoHelperBase implements Extra
return myFinal;
}
public void setName(String name) {
myName = name;
}
public void setDeclareFinal(boolean aFinal) {
myFinal = aFinal;
}
public void setToRemove(TIntArrayList toRemove) {
this.toRemove = toRemove;
}
@Override
public TIntArrayList parametersToRemove() {
return toRemove;
return myToRemove;
}
@Override
public int replaceFieldsWithGetters() {
return 0;//todo
return myReplaceFieldsWithGetters;
}
@Override
@@ -104,8 +101,4 @@ public class ExtractClosureHelper extends ExtractInfoHelperBase implements Extra
public boolean generateDelegate() {
return myGenerateDelegate;
}
public void setGenerateDelegate(boolean generateDelegate) {
myGenerateDelegate = generateDelegate;
}
}
@@ -24,14 +24,16 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
import org.jetbrains.plugins.groovy.refactoring.extract.ExtractUtil;
import org.jetbrains.plugins.groovy.refactoring.introduce.parameter.GrIntroduceParameterSettings;
/**
* @author Max Medvedev
*/
public abstract class ExtractClosureProcessorBase extends BaseRefactoringProcessor {
protected final ExtractClosureHelper myHelper;
protected final GrIntroduceParameterSettings myHelper;
private static final String EXTRACT_CLOSURE = "Extract closure";
public ExtractClosureProcessorBase(@NotNull ExtractClosureHelper helper) {
public ExtractClosureProcessorBase(@NotNull GrIntroduceParameterSettings helper) {
super(helper.getProject());
myHelper = helper;
}
@@ -48,14 +50,14 @@ public abstract class ExtractClosureProcessorBase extends BaseRefactoringProcess
@Override
public String getProcessedElementsHeader() {
return ExtractClosureHandler.EXTRACT_CLOSURE;
return EXTRACT_CLOSURE;
}
};
}
@Override
protected String getCommandName() {
return ExtractClosureHandler.EXTRACT_CLOSURE;
return EXTRACT_CLOSURE;
}
protected GrClosableBlock generateClosure() {
@@ -77,6 +79,6 @@ public abstract class ExtractClosureProcessorBase extends BaseRefactoringProcess
ExtractUtil.generateBody(myHelper, false, buffer);
buffer.append('}');
return GroovyPsiElementFactory.getInstance(myHelper.getProject()).createClosureFromText(buffer.toString(), myHelper.getOwner());
return GroovyPsiElementFactory.getInstance(myHelper.getProject()).createClosureFromText(buffer.toString(), myHelper.getToReplaceIn());
}
}
@@ -73,7 +73,8 @@ public class GroovyExtractMethodHandler implements RefactoringActionHandler {
}
try {
final InitialInfo initialInfo = GroovyExtractChooser.invoke(project, editor, file, model.getSelectionStart(), model.getSelectionEnd());
final InitialInfo initialInfo =
GroovyExtractChooser.invoke(project, editor, file, model.getSelectionStart(), model.getSelectionEnd(), true);
performRefactoring(initialInfo, editor);
}
catch (GrRefactoringError e) {
@@ -27,6 +27,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpres
* @author Max Medvedev
*/
public interface GrIntroduceContext {
@NotNull
Project getProject();
Editor getEditor();
@@ -38,12 +38,12 @@ public class GrIntroduceContextImpl implements GrIntroduceContext {
@Nullable private final GrVariable var;
@NotNull private final PsiElement place;
public GrIntroduceContextImpl(Project project,
Editor editor,
@Nullable GrExpression expression,
@Nullable GrVariable var,
PsiElement[] occurrences,
PsiElement scope) {
public GrIntroduceContextImpl(@NotNull Project project,
Editor editor,
@Nullable GrExpression expression,
@Nullable GrVariable var,
@NotNull PsiElement[] occurrences,
PsiElement scope) {
LOG.assertTrue(expression != null || var != null);
this.project = project;
@@ -55,6 +55,7 @@ public class GrIntroduceContextImpl implements GrIntroduceContext {
this.place = expression == null ? var : expression;
}
@NotNull
public Project getProject() {
return project;
}
@@ -91,14 +91,14 @@ public abstract class GrIntroduceHandlerBase<Settings extends GrIntroduceSetting
expression != null;
expression = PsiTreeUtil.getParentOfType(expression, GrExpression.class)) {
if (expressions.contains(expression)) continue;
if (expressionIsNotCorrect(expression)) continue;
if (expressionIsIncorrect(expression)) continue;
expressions.add(expression);
}
return expressions;
}
private static boolean expressionIsNotCorrect(GrExpression expression) {
private static boolean expressionIsIncorrect(GrExpression expression) {
if (expression instanceof GrParenthesizedExpression) return true;
if (expression instanceof GrSuperReferenceExpression) return true;
if (expression.getType() == PsiType.VOID) return true;
@@ -297,23 +297,48 @@ public abstract class GrIntroduceHandlerBase<Settings extends GrIntroduceSetting
return var;
}
@Nullable
public static GrVariable findVariable(GrStatement statement) {
if (!(statement instanceof GrVariableDeclaration)) return null;
final GrVariableDeclaration variableDeclaration = (GrVariableDeclaration)statement;
final GrVariable[] variables = variableDeclaration.getVariables();
GrVariable var = null;
if (variables.length == 1) {
var = variables[0];
}
if (var instanceof GrParameter || var instanceof GrField) {
return null;
}
return var;
}
@Nullable
public static GrExpression findExpression(PsiFile file, int startOffset, int endOffset) {
GrExpression selectedExpr = GroovyRefactoringUtil.findElementInRange(file, startOffset, endOffset, GrExpression.class);
while (selectedExpr instanceof GrParenthesizedExpression) selectedExpr = ((GrParenthesizedExpression)selectedExpr).getOperand();
if (selectedExpr == null) return null;
PsiType type = selectedExpr.getType();
return findExpression(selectedExpr);
}
@Nullable
public static GrExpression findExpression(GrStatement selectedExpr) {
if (!(selectedExpr instanceof GrExpression)) return null;
GrExpression selected = (GrExpression)selectedExpr;
while (selected instanceof GrParenthesizedExpression) selected = ((GrParenthesizedExpression)selected).getOperand();
if (selected == null) return null;
PsiType type = selected.getType();
if (type != null) type = TypeConversionUtil.erasure(type);
if (PsiType.VOID.equals(type)) {
throw new GrRefactoringError(GroovyRefactoringBundle.message("selected.expression.has.void.type"));
}
if (expressionIsNotCorrect(selectedExpr)) {
if (expressionIsIncorrect(selected)) {
throw new GrRefactoringError(GroovyRefactoringBundle.message("selected.block.should.represent.an.expression"));
}
return selectedExpr;
return selected;
}
@Nullable
@@ -21,6 +21,7 @@ import org.jetbrains.annotations.Nullable;
public interface GrIntroduceSettings {
@Nullable
String getName();
boolean replaceAllOccurrences();
@Nullable
@@ -81,21 +81,19 @@ import java.util.List;
public class GrIntroduceClosureParameterProcessor extends BaseRefactoringProcessor {
private static final Logger LOG = Logger.getInstance(GrIntroduceClosureParameterProcessor.class);
private GrIntroduceParameterSettings mySettings;
private GrIntroduceParameterContext myContext;
private GrIntroduceExpressionSettings mySettings;
private GrClosableBlock toReplaceIn;
private PsiElement toSearchFor;
private GrExpressionWrapper myParameterInitializer;
private GroovyPsiElementFactory myFactory = GroovyPsiElementFactory.getInstance(myProject);
public GrIntroduceClosureParameterProcessor(GrIntroduceParameterSettings settings, GrIntroduceParameterContext context) {
super(context.getProject(), null);
public GrIntroduceClosureParameterProcessor(GrIntroduceExpressionSettings settings) {
super(settings.getProject(), null);
mySettings = settings;
myContext = context;
toReplaceIn = (GrClosableBlock)myContext.getToReplaceIn();
toSearchFor = myContext.getToSearchFor();
myParameterInitializer = new GrExpressionWrapper(this.myContext.getExpression());
toReplaceIn = (GrClosableBlock)mySettings.getToReplaceIn();
toSearchFor = mySettings.getToSearchFor();
myParameterInitializer = new GrExpressionWrapper(mySettings.getExpression());
}
@NotNull
@@ -123,15 +121,16 @@ public class GrIntroduceClosureParameterProcessor extends BaseRefactoringProcess
detectAccessibilityConflicts(usagesIn, conflicts);
}
if (myContext.getExpression() != null && toSearchFor instanceof PsiMember) {
final GrExpression expression = mySettings.getExpression();
if (expression != null && toSearchFor instanceof PsiMember) {
final AnySupers anySupers = new AnySupers();
myContext.getExpression().accept(anySupers);
expression.accept(anySupers);
if (anySupers.isResult()) {
final PsiElement containingClass = PsiUtil.getFileOrClassContext(toReplaceIn);
for (UsageInfo usageInfo : usagesIn) {
if (!(usageInfo.getElement() instanceof PsiMethod) && !(usageInfo instanceof InternalUsageInfo)) {
if (!PsiTreeUtil.isAncestor(containingClass, usageInfo.getElement(), false)) {
conflicts.putValue(myContext.getExpression(), RefactoringBundle
conflicts.putValue(expression, RefactoringBundle
.message("parameter.initializer.contains.0.but.not.all.calls.to.method.are.in.its.class", CommonRefactoringUtil.htmlEmphasize(PsiKeyword.SUPER)));
break;
}
@@ -152,10 +151,11 @@ public class GrIntroduceClosureParameterProcessor extends BaseRefactoringProcess
private void detectAccessibilityConflicts(final UsageInfo[] usageArray, MultiMap<PsiElement, String> conflicts) {
//todo whole method
if (myContext.getExpression() == null) return;
final GrExpression expression = mySettings.getExpression();
if (expression == null) return;
final ReferencedElementsCollector collector = new ReferencedElementsCollector();
myContext.getExpression().accept(collector);
expression.accept(collector);
final List<PsiElement> result = collector.getResult();
if (result.isEmpty()) return;
@@ -223,14 +223,14 @@ public class GrIntroduceClosureParameterProcessor extends BaseRefactoringProcess
}
if (mySettings.replaceAllOccurrences()) {
PsiElement[] exprs = myContext.getOccurrences();
PsiElement[] exprs = GroovyIntroduceParameterUtil.getOccurrences(mySettings);
for (PsiElement expr : exprs) {
result.add(new InternalUsageInfo(expr));
}
}
else {
if (myContext.getExpression() != null) {
result.add(new InternalUsageInfo(myContext.getExpression()));
if (mySettings.getExpression() != null) {
result.add(new InternalUsageInfo(mySettings.getExpression()));
}
}
@@ -314,8 +314,9 @@ public class GrIntroduceClosureParameterProcessor extends BaseRefactoringProcess
processClosure(usages);
}
if (myContext.getVar() != null && mySettings.removeLocalVariable()) {
myContext.getVar().delete();
final GrVariable var = mySettings.getVar();
if (var != null && mySettings.removeLocalVariable()) {
var.delete();
}
}
@@ -611,7 +612,7 @@ public class GrIntroduceClosureParameterProcessor extends BaseRefactoringProcess
@Override
protected String getCommandName() {
return RefactoringBundle.message("introduce.parameter.command", UsageViewUtil.getDescriptiveName(myContext.getToReplaceIn()));
return RefactoringBundle.message("introduce.parameter.command", UsageViewUtil.getDescriptiveName(mySettings.getToReplaceIn()));
}
@@ -13,24 +13,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.refactoring.extract.closure;
package org.jetbrains.plugins.groovy.refactoring.introduce.parameter;
import com.intellij.lang.refactoring.RefactoringSupportProvider;
import com.intellij.refactoring.RefactoringActionHandler;
import com.intellij.refactoring.actions.BasePlatformRefactoringAction;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
/**
* @author Max Medvedev
*/
public class ExtractClosureAction extends BasePlatformRefactoringAction {
@Override
protected RefactoringActionHandler getRefactoringHandler(@NotNull RefactoringSupportProvider provider) {
return new ExtractClosureHandler();
}
public interface GrIntroduceExpressionSettings extends GrIntroduceParameterSettings {
@Nullable
GrVariable getVar();
@Nullable
GrExpression getExpression();
@Override
protected boolean isAvailableInEditorOnly() {
return true;
}
}
@@ -0,0 +1,61 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.plugins.groovy.refactoring.introduce.parameter;
import com.intellij.psi.PsiType;
import gnu.trove.TIntArrayList;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.refactoring.extract.closure.ExtractClosureHelperImpl;
/**
* @author Max Medvedev
*/
public class GrIntroduceExpressionSettingsImpl extends ExtractClosureHelperImpl implements GrIntroduceExpressionSettings {
private final GrExpression myExpr;
private final GrVariable myVar;
private final PsiType mySelectedType;
public GrIntroduceExpressionSettingsImpl(IntroduceParameterInfo info,
String name,
boolean declareFinal,
TIntArrayList toRemove,
boolean generateDelegate,
int replaceFieldsWithGetters,
GrExpression expr,
GrVariable var,
PsiType selectedType) {
super(info, name, declareFinal, toRemove, generateDelegate, replaceFieldsWithGetters);
myExpr = expr;
myVar = var;
mySelectedType = selectedType;
}
@Override
public GrVariable getVar() {
return myVar;
}
@Override
public GrExpression getExpression() {
return myExpr;
}
@Override
public PsiType getSelectedType() {
return mySelectedType;
}
}
@@ -15,35 +15,37 @@
*/
package org.jetbrains.plugins.groovy.refactoring.introduce.parameter;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiType;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.refactoring.BaseRefactoringProcessor;
import com.intellij.refactoring.JavaRefactoringSettings;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.ui.NameSuggestionsField;
import com.intellij.refactoring.ui.RefactoringDialog;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ui.GridBag;
import gnu.trove.TIntArrayList;
import gnu.trove.TObjectIntHashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.GroovyFileType;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrParametersOwner;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames;
import org.jetbrains.plugins.groovy.refactoring.GrRefactoringError;
import org.jetbrains.plugins.groovy.refactoring.GroovyNameSuggestionUtil;
import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringBundle;
import org.jetbrains.plugins.groovy.refactoring.HelpID;
import org.jetbrains.plugins.groovy.refactoring.extract.closure.ExtractClosureFromMethodProcessor;
import org.jetbrains.plugins.groovy.refactoring.extract.closure.ExtractClosureHelperImpl;
import org.jetbrains.plugins.groovy.refactoring.introduce.GrIntroduceContext;
import org.jetbrains.plugins.groovy.refactoring.introduce.GrIntroduceContextImpl;
import org.jetbrains.plugins.groovy.refactoring.introduce.GrIntroduceDialog;
import org.jetbrains.plugins.groovy.refactoring.introduce.GrIntroduceHandlerBase;
import org.jetbrains.plugins.groovy.refactoring.introduce.field.GroovyFieldValidator;
import org.jetbrains.plugins.groovy.refactoring.ui.GrTypeComboBox;
@@ -68,12 +70,14 @@ public class GrIntroduceParameterDialog extends RefactoringDialog implements GrI
private JLabel myTypeLabel;
private JLabel myNameLabel;
private JCheckBox myChangeVarUsages;
private GrIntroduceParameterContext myContext;
private IntroduceParameterInfo myInfo;
TObjectIntHashMap<JCheckBox> toRemoveCBs;
public GrIntroduceParameterDialog(GrIntroduceParameterContext context, TObjectIntHashMap<GrParameter> parametersToRemove) {
super(context.getProject(), true);
myContext = context;
public GrIntroduceParameterDialog(IntroduceParameterInfo info) {
super(info.getProject(), true);
myInfo = info;
TObjectIntHashMap<GrParameter> parametersToRemove = GroovyIntroduceParameterUtil.findParametersToRemove(info);
toRemoveCBs = new TObjectIntHashMap<JCheckBox>(parametersToRemove.size());
for (Object p : parametersToRemove.keys()) {
JCheckBox cb = new JCheckBox(GroovyRefactoringBundle.message("remove.parameter.0.no.longer.used", ((GrParameter)p).getName()));
@@ -83,11 +87,7 @@ public class GrIntroduceParameterDialog extends RefactoringDialog implements GrI
JavaRefactoringSettings settings = JavaRefactoringSettings.getInstance();
if (context.getOccurrences().length < 2) { //todo
myReplaceAllOccurrencesCheckBox.setSelected(true);
myReplaceAllOccurrencesCheckBox.setVisible(false);
}
if (myContext.getVar() == null) {
if (myInfo.getStatements().length == 1 && GrIntroduceHandlerBase.findVariable(myInfo.getStatements()[0]) == null) {
myRemoveLocalVariableCheckBox.setSelected(false);
myRemoveLocalVariableCheckBox.setVisible(false);
}
@@ -99,10 +99,10 @@ public class GrIntroduceParameterDialog extends RefactoringDialog implements GrI
myDeclareFinalCheckBox.setSelected(hasFinalModifier());
myChangeVarUsages.setVisible(context.getToReplaceIn() instanceof GrClosableBlock && context.getToSearchFor() instanceof GrVariable);
myChangeVarUsages.setVisible(info.getToReplaceIn() instanceof GrClosableBlock && info.getToSearchFor() instanceof GrVariable);
myChangeVarUsages.setSelected(true);
myDelegateViaOverloadingMethodCheckBox.setVisible(context.getToSearchFor() != null);
myDelegateViaOverloadingMethodCheckBox.setVisible(info.getToSearchFor() != null);
setTitle(RefactoringBundle.message("introduce.parameter.title"));
init();
@@ -110,7 +110,7 @@ public class GrIntroduceParameterDialog extends RefactoringDialog implements GrI
private void initReplaceFieldsWithGetters(JavaRefactoringSettings settings) {
final PsiField[] usedFields = GroovyIntroduceParameterUtil.findUsedFieldsWithGetters(myContext.getExpression(), getContainingClass());
final PsiField[] usedFields = GroovyIntroduceParameterUtil.findUsedFieldsWithGetters(myInfo.getStatements(), getContainingClass());
myGetterPanel.setVisible(usedFields.length > 0);
switch (settings.INTRODUCE_PARAMETER_REPLACE_FIELDS_WITH_GETTERS) {
case REPLACE_FIELDS_WITH_GETTERS_ALL:
@@ -127,7 +127,7 @@ public class GrIntroduceParameterDialog extends RefactoringDialog implements GrI
@Nullable
private PsiClass getContainingClass() {
final GrParametersOwner toReplaceIn = myContext.getToReplaceIn();
final GrParametersOwner toReplaceIn = myInfo.getToReplaceIn();
if (toReplaceIn instanceof GrMethod) {
return ((GrMethod)toReplaceIn).getContainingClass();
}
@@ -144,27 +144,39 @@ public class GrIntroduceParameterDialog extends RefactoringDialog implements GrI
@Override
protected void doAction() {
saveSettings();
GrIntroduceParameterSettings settings = new GrIntroduceParameterSettingsImpl(
myNameSuggestionsField.getEnteredName(),
myReplaceAllOccurrencesCheckBox.isSelected(),
myTypeComboBox.getSelectedType(),
myDeclareFinalCheckBox.isSelected(),
myDelegateViaOverloadingMethodCheckBox.isSelected(),
getParametersToRemove(),
getReplaceFieldsWithGetter(),
myRemoveLocalVariableCheckBox.isSelected());
final GrParametersOwner toReplaceIn = myInfo.getToReplaceIn();
final PsiType selectedType = myTypeComboBox.getSelectedType();
final BaseRefactoringProcessor processor;
if (myContext.getToReplaceIn() instanceof GrMethod) {
processor = new GrIntroduceParameterProcessor(settings, myContext);
final GrExpression expr = findExpr();
final GrVariable var = findVar();
if ((expr == null && var == null) || selectedType != null && selectedType.equalsToText(GroovyCommonClassNames.GROOVY_LANG_CLOSURE)) {
GrIntroduceParameterSettings settings = new ExtractClosureHelperImpl(myInfo,
myNameSuggestionsField.getEnteredName(),
myDeclareFinalCheckBox.isSelected(),
getParametersToRemove(),
myDelegateViaOverloadingMethodCheckBox.isSelected(),
getReplaceFieldsWithGetter());
invokeRefactoring(new ExtractClosureFromMethodProcessor(settings));
}
else {
if (!myChangeVarUsages.isSelected() && myContext.getToSearchFor() != null) {
myContext = new GrIntroduceParameterContextImpl(myContext, myContext.getToReplaceIn(), null);
GrIntroduceExpressionSettings settings = new GrIntroduceExpressionSettingsImpl(myInfo,
myNameSuggestionsField.getEnteredName(),
myDeclareFinalCheckBox.isSelected(),
getParametersToRemove(),
myDelegateViaOverloadingMethodCheckBox.isSelected(),
getReplaceFieldsWithGetter(),
expr,
var,
myTypeComboBox.getSelectedType());
if (toReplaceIn instanceof GrMethod) {
invokeRefactoring(new GrIntroduceParameterProcessor(settings));
}
else {
invokeRefactoring(new GrIntroduceClosureParameterProcessor(settings));
}
processor = new GrIntroduceClosureParameterProcessor(settings, myContext);
}
invokeRefactoring(processor);
}
private void saveSettings() {
@@ -224,101 +236,53 @@ public class GrIntroduceParameterDialog extends RefactoringDialog implements GrI
}
private void createUIComponents() {
if (myContext.getVar() != null) {
myTypeComboBox = GrTypeComboBox.createTypeComboBoxWithDefType(myContext.getVar().getDeclaredType());
final GrVariable var = findVar();
final GrExpression expr = findExpr();
if (var != null) {
myTypeComboBox = GrTypeComboBox.createTypeComboBoxWithDefType(var.getDeclaredType());
}
else if (expr != null) {
myTypeComboBox = GrTypeComboBox.createTypeComboBoxFromExpression(expr);
}
else {
myTypeComboBox = GrTypeComboBox.createTypeComboBoxFromExpression(myContext.getExpression());
myTypeComboBox = GrTypeComboBox.createEmptyTypeComboBox();
}
myTypeComboBox.addType(JavaPsiFacade.getElementFactory(myProject).createTypeFromText(GroovyCommonClassNames.GROOVY_LANG_CLOSURE, myInfo.getContext()));
String[] possibleNames;
final GrIntroduceContext
introduceContext = new GrIntroduceContextImpl(myProject, null, myContext.getExpression(), myContext.getVar(), PsiElement.EMPTY_ARRAY,
myContext.getToReplaceIn());
final GrIntroduceContext introduceContext = new GrIntroduceContextImpl(myProject, null, expr, var, PsiElement.EMPTY_ARRAY, myInfo.getToReplaceIn());
final GroovyFieldValidator validator = new GroovyFieldValidator(introduceContext);
if (myContext.getExpression() != null) {
possibleNames = GroovyNameSuggestionUtil.suggestVariableNames(myContext.getExpression(), validator, true);
if (expr != null) {
possibleNames = GroovyNameSuggestionUtil.suggestVariableNames(expr, validator, true);
}
else if (var != null) {
possibleNames = GroovyNameSuggestionUtil.suggestVariableNameByType(var.getType(), validator);
}
else {
possibleNames = GroovyNameSuggestionUtil.suggestVariableNameByType(myContext.getVar().getType(), validator);
possibleNames = ArrayUtil.EMPTY_STRING_ARRAY;
}
if (myContext.getVar() != null) {
if (var != null) {
String[] arr = new String[possibleNames.length + 1];
arr[0] = myContext.getVar().getName();
arr[0] = var.getName();
System.arraycopy(possibleNames, 0, arr, 1, possibleNames.length);
possibleNames = arr;
}
myNameSuggestionsField = new NameSuggestionsField(possibleNames, myContext.getProject(), GroovyFileType.GROOVY_FILE_TYPE);
myNameSuggestionsField = new NameSuggestionsField(possibleNames, myProject, GroovyFileType.GROOVY_FILE_TYPE);
}
static class GrIntroduceParameterSettingsImpl implements GrIntroduceParameterSettings {
@Nullable
private GrVariable findVar() {
final GrStatement[] statements = myInfo.getStatements();
if (statements.length > 1) return null;
return GrIntroduceHandlerBase.findVariable(statements[0]);
}
private String myName;
private boolean myReplaceAllOccurrences;
private PsiType mySelectedType;
private boolean myDeclareFinal;
private boolean myIsGenerateDelegate;
private TIntArrayList myParameterToRemove;
private int myReplaceFieldWithGetters;
private boolean myRemoveLocalVariable;
GrIntroduceParameterSettingsImpl(String name,
boolean replaceAllOccurrences,
PsiType selectedType,
boolean declareFinal,
boolean isGenerateDelegate,
TIntArrayList parameterToRemove,
int replaceFieldWithGetters,
boolean removeLocalVariable) {
myName = name;
myReplaceAllOccurrences = replaceAllOccurrences;
mySelectedType = selectedType;
myDeclareFinal = declareFinal;
myIsGenerateDelegate = isGenerateDelegate;
myParameterToRemove = parameterToRemove;
myReplaceFieldWithGetters = replaceFieldWithGetters;
myRemoveLocalVariable = removeLocalVariable;
}
@Override
public String getName() {
return myName;
}
@Override
public boolean replaceAllOccurrences() {
return myReplaceAllOccurrences;
}
@Override
public PsiType getSelectedType() {
return mySelectedType;
}
@Override
public boolean declareFinal() {
return myDeclareFinal;
}
@Override
public boolean removeLocalVariable() {
return myRemoveLocalVariable;
}
@Override
public boolean generateDelegate() {
return myIsGenerateDelegate;
}
@NotNull
@Override
public TIntArrayList parametersToRemove() {
return myParameterToRemove;
}
@Override
public int replaceFieldsWithGetters() {
return myReplaceFieldWithGetters;
}
@Nullable
private GrExpression findExpr() {
final GrStatement[] statements = myInfo.getStatements();
if (statements.length > 1) return null;
return GrIntroduceHandlerBase.findExpression(statements[0]);
}
}
@@ -17,16 +17,16 @@ package org.jetbrains.plugins.groovy.refactoring.introduce.parameter;
import com.intellij.ide.util.SuperMethodWarningUtil;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.SelectionModel;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.util.Pass;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.refactoring.IntroduceTargetChooser;
import com.intellij.refactoring.RefactoringActionHandler;
@@ -34,11 +34,8 @@ import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.intellij.util.Function;
import com.intellij.util.PairFunction;
import com.intellij.util.Processor;
import gnu.trove.TObjectIntHashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrParametersOwner;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
@@ -46,18 +43,14 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlo
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import org.jetbrains.plugins.groovy.refactoring.GrRefactoringError;
import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringBundle;
import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringUtil;
import org.jetbrains.plugins.groovy.refactoring.introduce.GrIntroduceContext;
import org.jetbrains.plugins.groovy.refactoring.introduce.GrIntroduceContextImpl;
import org.jetbrains.plugins.groovy.refactoring.introduce.GrIntroduceDialog;
import org.jetbrains.plugins.groovy.refactoring.extract.GroovyExtractChooser;
import org.jetbrains.plugins.groovy.refactoring.extract.InitialInfo;
import org.jetbrains.plugins.groovy.refactoring.introduce.GrIntroduceHandlerBase;
import org.jetbrains.plugins.groovy.refactoring.ui.MethodOrClosureScopeChooser;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static org.jetbrains.plugins.groovy.refactoring.HelpID.GROOVY_INTRODUCE_PARAMETER;
@@ -66,8 +59,6 @@ import static org.jetbrains.plugins.groovy.refactoring.HelpID.GROOVY_INTRODUCE_P
* @author Maxim.Medvedev
*/
public class GrIntroduceParameterHandler implements RefactoringActionHandler, MethodOrClosureScopeChooser.JBPopupOwner {
private static final Logger LOG = Logger.getInstance(GrIntroduceParameterHandler.class);
private JBPopup myEnclosingMethodsPopup;
public void invoke(final @NotNull Project project, final Editor editor, final PsiFile file, final @Nullable DataContext dataContext) {
@@ -91,18 +82,16 @@ public class GrIntroduceParameterHandler implements RefactoringActionHandler, Me
selectionModel.setSelection(textRange.getStartOffset(), textRange.getEndOffset());
}
else {
final Pass<GrExpression> callback = new Pass<GrExpression>() {
IntroduceTargetChooser.showChooser(editor, expressions, new Pass<GrExpression>() {
public void pass(final GrExpression selectedValue) {
invoke(project, editor, file, selectedValue.getTextRange().getStartOffset(), selectedValue.getTextRange().getEndOffset());
}
};
final Function<GrExpression, String> renderer = new Function<GrExpression, String>() {
}, new Function<GrExpression, String>() {
@Override
public String fun(GrExpression grExpression) {
return grExpression.getText();
}
};
IntroduceTargetChooser.showChooser(editor, expressions, callback, renderer
}
);
return;
}
@@ -112,33 +101,17 @@ public class GrIntroduceParameterHandler implements RefactoringActionHandler, Me
private void invoke(final Project project, final Editor editor, PsiFile file, int startOffset, int endOffset) {
try {
PsiDocumentManager.getInstance(project).commitAllDocuments();
if (!(file instanceof GroovyFileBase)) {
throw new GrRefactoringError(GroovyRefactoringBundle.message("only.in.groovy.files"));
}
if (!CommonRefactoringUtil.checkReadOnlyStatus(project, file)) {
throw new GrRefactoringError(RefactoringBundle.message("readonly.occurences.found"));
}
GrExpression selectedExpr = GrIntroduceHandlerBase.findExpression(file, startOffset, endOffset);
final GrVariable variable = GrIntroduceHandlerBase.findVariable(file, startOffset, endOffset);
if (variable == null && selectedExpr == null) {
throw new GrRefactoringError(null);
}
findScope(selectedExpr, variable, editor, project);
final InitialInfo initialInfo = GroovyExtractChooser.invoke(project, editor, file, startOffset, endOffset, false);
findScope(initialInfo, editor);
}
catch (GrRefactoringError e) {
CommonRefactoringUtil.showErrorHint(project, editor, RefactoringBundle.getCannotRefactorMessage(e.getMessage()), RefactoringBundle.message("introduce.parameter.title"),
GROOVY_INTRODUCE_PARAMETER);
if (ApplicationManager.getApplication().isUnitTestMode()) throw e;
CommonRefactoringUtil.showErrorHint(project, editor, e.getMessage(), RefactoringBundle.message("introduce.parameter.title"), GROOVY_INTRODUCE_PARAMETER);
}
}
private void findScope(@Nullable final GrExpression expression, @Nullable final GrVariable variable, @NotNull final Editor editor, @NotNull final Project project) {
LOG.assertTrue(expression != null || variable != null);
PsiElement place = expression == null ? variable : expression;
private void findScope(@NotNull final InitialInfo initialInfo, @NotNull final Editor editor) {
PsiElement place = initialInfo.getContext();
final List<GrParametersOwner> scopes = new ArrayList<GrParametersOwner>();
while (true) {
final GrParametersOwner parent = PsiTreeUtil.getParentOfType(place, GrMethod.class, GrClosableBlock.class);
@@ -160,13 +133,13 @@ public class GrIntroduceParameterHandler implements RefactoringActionHandler, Me
else {
toSearchFor = MethodOrClosureScopeChooser.findVariableToUse(owner);
}
getContext(project, editor, expression, variable, owner, toSearchFor);
showDialog(new IntroduceParameterInfoImpl(initialInfo, owner, toSearchFor));
}
else {
myEnclosingMethodsPopup = MethodOrClosureScopeChooser.create(scopes, editor, this, new PairFunction<GrParametersOwner, PsiElement, Object>() {
@Override
public Object fun(GrParametersOwner owner, PsiElement element) {
getContext(project, editor, expression, variable, owner, element);
showDialog(new IntroduceParameterInfoImpl(initialInfo, owner, element));
return null;
}
});
@@ -179,56 +152,13 @@ public class GrIntroduceParameterHandler implements RefactoringActionHandler, Me
return myEnclosingMethodsPopup;
}
protected void getContext(@NotNull Project project,
@NotNull Editor editor,
@Nullable GrExpression expression,
@Nullable GrVariable variable,
@NotNull GrParametersOwner toReplaceIn,
@Nullable PsiElement toSearchFor) {
LOG.assertTrue(expression != null || variable != null);
GrIntroduceContext context;
if (variable == null) {
final PsiElement[] occurrences = findOccurrences(expression, toReplaceIn);
context = new GrIntroduceContextImpl(project, editor, expression, variable, occurrences, toReplaceIn);
}
else {
final List<PsiElement> list = Collections.synchronizedList(new ArrayList<PsiElement>());
ReferencesSearch.search(variable, new LocalSearchScope(toReplaceIn)).forEach(new Processor<PsiReference>() {
@Override
public boolean process(PsiReference psiReference) {
final PsiElement element = psiReference.getElement();
if (element != null) {
list.add(element);
}
return true;
}
});
context = new GrIntroduceContextImpl(project, editor, variable.getInitializerGroovy(), variable, list.toArray(new PsiElement[list.size()]), toReplaceIn);
}
showDialog(new GrIntroduceParameterContextImpl(context, toReplaceIn, toSearchFor));
//method to hack in tests
protected void showDialog(IntroduceParameterInfo info) {
new GrIntroduceParameterDialog(info).show();
}
protected void showDialog(GrIntroduceParameterContext context) {
TObjectIntHashMap<GrParameter> toRemove = GroovyIntroduceParameterUtil.findParametersToRemove(context);
final GrIntroduceDialog<GrIntroduceParameterSettings> dialog = new GrIntroduceParameterDialog(context, toRemove);
dialog.show();
}
@NotNull
private static PsiElement[] findOccurrences(@NotNull GrExpression expression, PsiElement scope) {
final PsiElement expr = PsiUtil.skipParentheses(expression, false);
if (expr == null) return PsiElement.EMPTY_ARRAY;
final PsiElement[] occurrences = GroovyRefactoringUtil.getExpressionOccurrences(expr, scope);
if (occurrences == null || occurrences.length == 0) {
throw new GrRefactoringError(GroovyRefactoringBundle.message("no.occurrences.found"));
}
return occurrences;
}
@Override
public void invoke(@NotNull Project project, @NotNull PsiElement[] elements, DataContext dataContext) {
// Does nothing
@@ -38,6 +38,7 @@ import com.intellij.util.containers.MultiMap;
import gnu.trove.TIntArrayList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
@@ -51,18 +52,16 @@ import java.util.Collection;
public class GrIntroduceParameterProcessor extends BaseRefactoringProcessor implements IntroduceParameterData {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.plugins.groovy.refactoring.introduce.parameter.GrIntroduceParameterProcessor");
private final GrIntroduceParameterSettings mySettings;
private final GrIntroduceParameterContext myContext;
private final GrIntroduceExpressionSettings mySettings;
private IntroduceParameterData.ExpressionWrapper myParameterInitializer;
public GrIntroduceParameterProcessor(GrIntroduceParameterSettings settings, GrIntroduceParameterContext context) {
super(context.getProject());
public GrIntroduceParameterProcessor(GrIntroduceExpressionSettings settings) {
super(settings.getProject());
this.mySettings = settings;
this.myContext = context;
LOG.assertTrue(myContext.getToReplaceIn() instanceof GrMethod);
LOG.assertTrue(myContext.getToSearchFor() instanceof PsiMethod);
myParameterInitializer = new GrExpressionWrapper(this.myContext.getExpression());
LOG.assertTrue(mySettings.getToReplaceIn() instanceof GrMethod);
LOG.assertTrue(mySettings.getToSearchFor() instanceof PsiMethod);
myParameterInitializer = new GrExpressionWrapper(mySettings.getExpression());
}
@NotNull
@@ -72,7 +71,7 @@ public class GrIntroduceParameterProcessor extends BaseRefactoringProcessor impl
@NotNull
@Override
public PsiElement[] getElements() {
return new PsiElement[]{myContext.getToSearchFor()};
return new PsiElement[]{mySettings.getToSearchFor()};
}
@Override
@@ -88,21 +87,21 @@ public class GrIntroduceParameterProcessor extends BaseRefactoringProcessor impl
MultiMap<PsiElement, String> conflicts = new MultiMap<PsiElement, String>();
if (!mySettings.generateDelegate()) {
GroovyIntroduceParameterUtil.detectAccessibilityConflicts(myContext.getExpression(), usagesIn, conflicts,
GroovyIntroduceParameterUtil.detectAccessibilityConflicts(mySettings.getExpression(), usagesIn, conflicts,
mySettings.replaceFieldsWithGetters() != IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_NONE,
myProject
);
}
final GrMethod toReplaceIn = (GrMethod)myContext.getToReplaceIn();
if (myContext.getExpression() != null && !toReplaceIn.hasModifierProperty(PsiModifier.PRIVATE)) {
final GrMethod toReplaceIn = (GrMethod)mySettings.getToReplaceIn();
if (mySettings.getExpression() != null && !toReplaceIn.hasModifierProperty(PsiModifier.PRIVATE)) {
final AnySupers anySupers = new AnySupers();
myContext.getExpression().accept(anySupers);
mySettings.getExpression().accept(anySupers);
if (anySupers.isResult()) {
for (UsageInfo usageInfo : usagesIn) {
if (!(usageInfo.getElement() instanceof PsiMethod) && !(usageInfo instanceof InternalUsageInfo)) {
if (!PsiTreeUtil.isAncestor(toReplaceIn.getContainingClass(), usageInfo.getElement(), false)) {
conflicts.putValue(myContext.getExpression(),
conflicts.putValue(mySettings.getExpression(),
RefactoringBundle.message("parameter.initializer.contains.0.but.not.all.calls.to.method.are.in.its.class",
CommonRefactoringUtil.htmlEmphasize(PsiKeyword.SUPER)));
break;
@@ -124,7 +123,7 @@ public class GrIntroduceParameterProcessor extends BaseRefactoringProcessor impl
protected UsageInfo[] findUsages() {
ArrayList<UsageInfo> result = new ArrayList<UsageInfo>();
final PsiMethod toSearchFor = ((PsiMethod)myContext.getToSearchFor());
final PsiMethod toSearchFor = ((PsiMethod)mySettings.getToSearchFor());
if (!mySettings.generateDelegate()) {
Collection<PsiReference> refs =
@@ -140,7 +139,7 @@ public class GrIntroduceParameterProcessor extends BaseRefactoringProcessor impl
else if (ref instanceof PsiClass) {
result.add(new NoConstructorClassUsageInfo((PsiClass)ref));
}
else if (!PsiTreeUtil.isAncestor(myContext.getToReplaceIn(), ref, false)) {
else if (!PsiTreeUtil.isAncestor(mySettings.getToReplaceIn(), ref, false)) {
result.add(new ExternalUsageInfo(ref));
}
else {
@@ -150,14 +149,14 @@ public class GrIntroduceParameterProcessor extends BaseRefactoringProcessor impl
}
if (mySettings.replaceAllOccurrences()) {
PsiElement[] exprs = myContext.getOccurrences();
PsiElement[] exprs = GroovyIntroduceParameterUtil.getOccurrences(mySettings);
for (PsiElement expr : exprs) {
result.add(new InternalUsageInfo(expr));
}
}
else {
if (myContext.getExpression() != null) {
result.add(new InternalUsageInfo(myContext.getExpression()));
if (mySettings.getExpression() != null) {
result.add(new InternalUsageInfo(mySettings.getExpression()));
}
}
@@ -181,8 +180,8 @@ public class GrIntroduceParameterProcessor extends BaseRefactoringProcessor impl
IntroduceParameterUtil.processUsages(usages, this);
final GrMethod toReplaceIn = (GrMethod)myContext.getToReplaceIn();
final PsiMethod toSearchFor = (PsiMethod)myContext.getToSearchFor();
final GrMethod toReplaceIn = (GrMethod)mySettings.getToReplaceIn();
final PsiMethod toSearchFor = (PsiMethod)mySettings.getToSearchFor();
final boolean methodsToProcessAreDifferent = toReplaceIn != toSearchFor;
if (mySettings.generateDelegate()) {
@@ -210,8 +209,6 @@ public class GrIntroduceParameterProcessor extends BaseRefactoringProcessor impl
IntroduceParameterUtil.changeMethodSignatureAndResolveFieldConflicts(new UsageInfo(toSearchFor), usages, this);
}
if (myContext.getVar() != null) myContext.getVar().delete();
// Replacing expression occurrences
for (UsageInfo usage : usages) {
if (usage instanceof ChangedMethodCallInfo) {
@@ -232,32 +229,33 @@ public class GrIntroduceParameterProcessor extends BaseRefactoringProcessor impl
}
}
if (myContext.getVar() != null && mySettings.removeLocalVariable()) {
myContext.getVar().delete();
final GrVariable var = mySettings.getVar();
if (var != null && mySettings.removeLocalVariable()) {
var.delete();
}
fieldConflictsResolver.fix();
}
@Override
protected String getCommandName() {
return RefactoringBundle.message("introduce.parameter.command", UsageViewUtil.getDescriptiveName(myContext.getToReplaceIn()));
return RefactoringBundle.message("introduce.parameter.command", UsageViewUtil.getDescriptiveName(mySettings.getToReplaceIn()));
}
@NotNull
@Override
public Project getProject() {
return myContext.getProject();
return mySettings.getProject();
}
@Override
public PsiMethod getMethodToReplaceIn() {
return (PsiMethod)myContext.getToReplaceIn();
return (PsiMethod)mySettings.getToReplaceIn();
}
@NotNull
@Override
public PsiMethod getMethodToSearchFor() {
return (PsiMethod)myContext.getToSearchFor();
return (PsiMethod)mySettings.getToSearchFor();
}
@Override
@@ -292,7 +290,7 @@ public class GrIntroduceParameterProcessor extends BaseRefactoringProcessor impl
final PsiType selectedType = mySettings.getSelectedType();
if (selectedType != null) return selectedType;
final PsiManager manager = PsiManager.getInstance(myProject);
final GlobalSearchScope resolveScope = myContext.getToReplaceIn().getResolveScope();
final GlobalSearchScope resolveScope = mySettings.getToReplaceIn().getResolveScope();
return PsiType.getJavaLangObject(manager, resolveScope);
}
@@ -15,14 +15,20 @@
*/
package org.jetbrains.plugins.groovy.refactoring.introduce.parameter;
import com.intellij.psi.PsiElement;
import gnu.trove.TIntArrayList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrParametersOwner;
import org.jetbrains.plugins.groovy.refactoring.extract.ExtractInfoHelper;
import org.jetbrains.plugins.groovy.refactoring.introduce.GrIntroduceSettings;
/**
* @author Maxim.Medvedev
*/
public interface GrIntroduceParameterSettings extends GrIntroduceSettings {
public interface GrIntroduceParameterSettings extends GrIntroduceSettings, ExtractInfoHelper {
boolean generateDelegate();
TIntArrayList parametersToRemove();
/**
@@ -33,4 +39,10 @@ public interface GrIntroduceParameterSettings extends GrIntroduceSettings {
boolean declareFinal();
boolean removeLocalVariable();
@NotNull
GrParametersOwner getToReplaceIn();
@Nullable
PsiElement getToSearchFor();
}
@@ -18,9 +18,9 @@ package org.jetbrains.plugins.groovy.refactoring.introduce.parameter;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.introduceParameter.ExternalUsageInfo;
import com.intellij.refactoring.introduceParameter.IntroduceParameterData;
@@ -42,6 +42,8 @@ import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
import org.jetbrains.plugins.groovy.lang.psi.GroovyRecursiveElementVisitor;
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrParametersOwner;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
@@ -56,8 +58,13 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMe
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrClosureSignature;
import org.jetbrains.plugins.groovy.lang.psi.impl.types.GrClosureSignatureUtil;
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import org.jetbrains.plugins.groovy.refactoring.GrRefactoringError;
import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringBundle;
import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringUtil;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
@@ -69,35 +76,13 @@ public class GroovyIntroduceParameterUtil {
private GroovyIntroduceParameterUtil() {
}
public static PsiField[] findUsedFieldsWithGetters(GrExpression expression, PsiClass containingClass) {
public static PsiField[] findUsedFieldsWithGetters(GrStatement[] statements, PsiClass containingClass) {
if (containingClass == null) return PsiField.EMPTY_ARRAY;
final FieldSearcher searcher = new FieldSearcher(containingClass);
expression.accept(searcher);
return searcher.getResult();
}
public static TObjectIntHashMap<GrParameter> findParametersToRemove(GrIntroduceParameterContext context) {
TObjectIntHashMap<GrParameter> toRemove = new TObjectIntHashMap<GrParameter>();
if (context.getVar() == null) {
final GrParametersOwner parametersOwner = context.getToReplaceIn();
final GrParameter[] parameters = parametersOwner.getParameters();
final GrExpression expr = context.getExpression();
for (int i = 0; i < parameters.length; i++) {
GrParameter parameter = parameters[i];
final boolean shouldRemove = ReferencesSearch.search(parameter).forEach(new Processor<PsiReference>() {
@Override
public boolean process(PsiReference ref) {
final PsiElement element = ref.getElement();
if (element == null) return false;
return PsiTreeUtil.isAncestor(expr, element, false);
}
});
if (shouldRemove) {
toRemove.put(parameter, i);
}
}
for (GrStatement statement : statements) {
statement.accept(searcher);
}
return toRemove;
return searcher.getResult();
}
@Nullable
@@ -311,6 +296,69 @@ public class GroovyIntroduceParameterUtil {
return method;
}
public static TObjectIntHashMap<GrParameter> findParametersToRemove(IntroduceParameterInfo helper) {
final TObjectIntHashMap<GrParameter> result = new TObjectIntHashMap<GrParameter>();
final GrStatement[] statements = helper.getStatements();
final int start = statements[0].getTextRange().getStartOffset();
final int end = statements[statements.length - 1].getTextRange().getEndOffset();
GrParameter[] parameters = helper.getToReplaceIn().getParameters();
for (int i = 0; i < parameters.length; i++) {
GrParameter parameter = parameters[i];
if (shouldRemove(parameter, start, end)) {
result.put(parameter, i);
}
}
return result;
}
private static boolean shouldRemove(GrParameter parameter, int start, int end) {
for (PsiReference reference : ReferencesSearch.search(parameter)) {
final PsiElement element = reference.getElement();
if (element == null) continue;
final int offset = element.getTextRange().getStartOffset();
if (offset < start || end <= offset) {
return false;
}
}
return true;
}
static PsiElement[] getOccurrences(GrIntroduceExpressionSettings settings) {
final GrParametersOwner scope = settings.getToReplaceIn();
final GrExpression expression = settings.getExpression();
if (expression != null) {
final PsiElement expr = PsiUtil.skipParentheses(expression, false);
if (expr == null) return PsiElement.EMPTY_ARRAY;
final PsiElement[] occurrences = GroovyRefactoringUtil.getExpressionOccurrences(expr, scope);
if (occurrences == null || occurrences.length == 0) {
throw new GrRefactoringError(GroovyRefactoringBundle.message("no.occurrences.found"));
}
return occurrences;
}
else {
final GrVariable var = settings.getVar();
LOG.assertTrue(var != null);
final List<PsiElement> list = Collections.synchronizedList(new ArrayList<PsiElement>());
ReferencesSearch.search(var, new LocalSearchScope(scope)).forEach(new Processor<PsiReference>() {
@Override
public boolean process(PsiReference psiReference) {
final PsiElement element = psiReference.getElement();
if (element != null) {
list.add(element);
}
return true;
}
});
return list.toArray(new PsiElement[list.size()]);
}
}
private static class FieldSearcher extends GroovyRecursiveElementVisitor {
PsiClass myClass;
private final List<PsiField> result = new ArrayList<PsiField>();
@@ -17,12 +17,12 @@ package org.jetbrains.plugins.groovy.refactoring.introduce.parameter;
import com.intellij.psi.PsiElement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrParametersOwner;
import org.jetbrains.plugins.groovy.refactoring.introduce.GrIntroduceContext;
import org.jetbrains.plugins.groovy.refactoring.extract.ExtractInfoHelper;
/**
* @author Max Medvedev
*/
public interface GrIntroduceParameterContext extends GrIntroduceContext {
public interface IntroduceParameterInfo extends ExtractInfoHelper {
PsiElement getToSearchFor();
GrParametersOwner getToReplaceIn();
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2011 JetBrains s.r.o.
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,28 +17,35 @@ package org.jetbrains.plugins.groovy.refactoring.introduce.parameter;
import com.intellij.psi.PsiElement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrParametersOwner;
import org.jetbrains.plugins.groovy.refactoring.introduce.GrIntroduceContext;
import org.jetbrains.plugins.groovy.refactoring.introduce.GrIntroduceContextImpl;
import org.jetbrains.plugins.groovy.refactoring.extract.ExtractInfoHelper;
import org.jetbrains.plugins.groovy.refactoring.extract.ExtractInfoHelperBase;
import org.jetbrains.plugins.groovy.refactoring.extract.InitialInfo;
/**
* @author Maxim.Medvedev
* @author Max Medvedev
*/
public class GrIntroduceParameterContextImpl extends GrIntroduceContextImpl implements GrIntroduceParameterContext {
private final PsiElement toSearchFor;
private final GrParametersOwner toReplaceIn;
public class IntroduceParameterInfoImpl extends ExtractInfoHelperBase implements IntroduceParameterInfo, ExtractInfoHelper {
private final GrParametersOwner myOwner;
private final PsiElement myToSearchFor;
public GrIntroduceParameterContextImpl(GrIntroduceContext context, GrParametersOwner toReplaceIn, PsiElement toSearchFor) {
super(context.getProject(), context.getEditor(), context.getExpression(), context.getVar(), context.getOccurrences(),
context.getScope());
this.toReplaceIn = toReplaceIn;
this.toSearchFor = toSearchFor;
public IntroduceParameterInfoImpl(InitialInfo info, GrParametersOwner owner, PsiElement toSearchFor) {
super(info);
myOwner = owner;
myToSearchFor = toSearchFor;
}
@Override
public String getName() {
throw new UnsupportedOperationException();
}
@Override
public PsiElement getToSearchFor() {
return toSearchFor;
return myToSearchFor;
}
@Override
public GrParametersOwner getToReplaceIn() {
return toReplaceIn;
return myOwner;
}
}
@@ -16,6 +16,7 @@
package org.jetbrains.plugins.groovy.refactoring.ui;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.ui.ComboBox;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import org.jetbrains.annotations.NotNull;
@@ -26,16 +27,16 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringUtil;
import javax.swing.*;
import java.util.*;
/**
* @author Maxim.Medvedev
*/
public class GrTypeComboBox extends JComboBox {
public class GrTypeComboBox extends ComboBox {
private static final Logger LOG = Logger.getInstance(GrTypeComboBox.class);
public static GrTypeComboBox createTypeComboBoxWithDefType(@Nullable PsiType type) {
return new GrTypeComboBox(type, null, true, null, null, false);
}
@@ -57,6 +58,10 @@ public class GrTypeComboBox extends JComboBox {
}
}
public static GrTypeComboBox createEmptyTypeComboBox() {
return new GrTypeComboBox(null, null, false, null, null, false);
}
/**
* @param type
* @param min
@@ -94,6 +99,10 @@ public class GrTypeComboBox extends JComboBox {
}
}
public void addType(PsiType type) {
addItem(new PsiTypeItem(type));
}
@Nullable
public PsiType getSelectedType() {
final Object selected = getSelectedItem();
@@ -16,12 +16,12 @@
package org.jetbrains.plugins.groovy.refactoring.extract.closure;
import com.intellij.psi.PsiElement
import com.intellij.refactoring.IntroduceParameterRefactoring
import gnu.trove.TIntArrayList
import org.jetbrains.annotations.NotNull
import org.jetbrains.plugins.groovy.LightGroovyTestCase
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrParametersOwner
import org.jetbrains.plugins.groovy.refactoring.extract.InitialInfo
import org.jetbrains.plugins.groovy.refactoring.introduce.parameter.GrIntroduceParameterHandler
import org.jetbrains.plugins.groovy.refactoring.introduce.parameter.GrIntroduceParameterSettings
import org.jetbrains.plugins.groovy.refactoring.introduce.parameter.IntroduceParameterInfo
import org.jetbrains.plugins.groovy.util.TestUtils
/**
@@ -40,25 +40,22 @@ public class ExtractClosureTest extends LightGroovyTestCase {
private void doTest(String before, String after, List<Integer> toRemove, List<Integer> notToUseAsParams) {
myFixture.configureByText '______________a____________________.groovy', before
def model = myFixture.editor.selectionModel
def handler = new ExtractClosureHandler() {
@Override
protected ExtractClosureHelper getSettings(@NotNull InitialInfo initialInfo, GrParametersOwner owner, PsiElement toSearchFor) {
def settings = new ExtractClosureHelper(initialInfo, owner, toSearchFor, "closure", true)
settings.setDeclareFinal(false)
settings.setGenerateDelegate(false)
settings.setName("closure")
settings.setToRemove(new TIntArrayList(toRemove as int[]))
def infos = settings.parameterInfos
for (int i: notToUseAsParams) {
infos[i].setPassAsParameter(false)
def handler = new GrIntroduceParameterHandler() {
@Override
protected void showDialog(IntroduceParameterInfo info) {
GrIntroduceParameterSettings helper = new ExtractClosureHelperImpl(info, "closure", false,
new TIntArrayList(toRemove as int[]), false,
IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_NONE)
for (p in notToUseAsParams) {
helper.parameterInfos[p].setPassAsParameter(false)
}
return settings
new ExtractClosureFromMethodProcessor(helper).run()
}
}
handler.invoke myFixture.project, myFixture.editor, myFixture.file, model.selectionStart, model.selectionEnd
handler.invoke myFixture.project, myFixture.editor, myFixture.file, null
myFixture.checkResult after
}
@@ -155,7 +152,7 @@ def foo(int x, int y) {
}
foo(2, 3)
''','''
''', '''
def foo(Closure closure) {
int a = 5
<selection>closure(a)</selection>
@@ -172,7 +169,7 @@ adventure()
def adventure() {
try {
<selection>killMonsters()
<selection><caret>killMonsters()
collectLoot()</selection>
} catch (ArrowToKneeException) {
becomeTownGuard()
@@ -194,7 +191,7 @@ def adventure(Closure closure) {
}
'''
}
void testExpression() {
doTest('''
adventure()
@@ -22,15 +22,17 @@ import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiType;
import com.intellij.psi.impl.source.PostprocessReformattingAspect;
import com.intellij.refactoring.BaseRefactoringProcessor;
import com.intellij.refactoring.IntroduceParameterRefactoring;
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
import gnu.trove.TIntArrayList;
import gnu.trove.TObjectIntHashMap;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
import org.jetbrains.plugins.groovy.refactoring.introduce.GrIntroduceHandlerBase;
import org.jetbrains.plugins.groovy.refactoring.introduce.parameter.*;
import org.jetbrains.plugins.groovy.util.TestUtils;
@@ -40,7 +42,7 @@ import java.io.File;
* @author Maxim.Medvedev
*/
public class GrIntroduceParameterTest extends LightCodeInsightFixtureTestCase {
protected String getBasePath() {
return TestUtils.getTestDataPath() + "refactoring/introduceParameterGroovy/" + getTestName(true) + '/';
}
@@ -114,17 +116,14 @@ public class GrIntroduceParameterTest extends LightCodeInsightFixtureTestCase {
try {
final GrIntroduceParameterHandler hackedHandler = new GrIntroduceParameterHandler() {
@Override
protected void showDialog(final GrIntroduceParameterContext context) {
final GrIntroduceParameterSettings hackedSettings =
getSettings(context, removeUnusedParameters, replaceFieldsWithGetters, declareFinal, generateDelegate);
BaseRefactoringProcessor processor;
if (context.getToReplaceIn() instanceof GrMethod) {
processor = new GrIntroduceParameterProcessor(hackedSettings, context);
protected void showDialog(IntroduceParameterInfo info) {
final GrIntroduceExpressionSettings hackedSettings = getSettings(info, removeUnusedParameters, replaceFieldsWithGetters, declareFinal, generateDelegate);
if (info.getToReplaceIn() instanceof GrMethod) {
new GrIntroduceParameterProcessor(hackedSettings).run();
}
else {
processor = new GrIntroduceClosureParameterProcessor(hackedSettings, context);
new GrIntroduceClosureParameterProcessor(hackedSettings).run();
}
processor.run();
}
};
hackedHandler.invoke(project, editor, file, null);
@@ -143,61 +142,23 @@ public class GrIntroduceParameterTest extends LightCodeInsightFixtureTestCase {
}, "introduce Parameter", null);
}
private static GrIntroduceParameterSettings getSettings(final GrIntroduceParameterContext context,
private static GrIntroduceExpressionSettings getSettings(final IntroduceParameterInfo context,
final boolean removeUnusedParameters,
final int replaceFieldsWithGetters,
final boolean declareFinal,
final boolean generateDelegate) {
return new GrIntroduceParameterSettings() {
@Override
public boolean generateDelegate() {
return generateDelegate;
}
@Override
public TIntArrayList parametersToRemove() {
if (removeUnusedParameters) {
final TObjectIntHashMap<GrParameter> parametersToRemove = GroovyIntroduceParameterUtil.findParametersToRemove(context);
TIntArrayList list = new TIntArrayList(parametersToRemove.size());
for (Object o : parametersToRemove.keys()) {
list.add(parametersToRemove.get((GrParameter)o));
}
return list;
}
return new TIntArrayList(0);
TIntArrayList toRemove = new TIntArrayList();
if (removeUnusedParameters) {
final TObjectIntHashMap<GrParameter> map = GroovyIntroduceParameterUtil.findParametersToRemove(context);
for (int i : map.getValues()) {
toRemove.add(i);
}
@Override
public int replaceFieldsWithGetters() {
return replaceFieldsWithGetters;
}
@Override
public boolean declareFinal() {
return declareFinal;
}
@Override
public boolean removeLocalVariable() {
return false;
}
@Override
public String getName() {
return "anObject";
}
@Override
public boolean replaceAllOccurrences() {
return true;
}
@Override
public PsiType getSelectedType() {
PsiType type = context.getVar() == null ? context.getExpression().getType() : context.getVar().getDeclaredType();
return TypesUtil.unboxPrimitiveTypeWrapper(type);
}
};
}
GrExpression expr = GrIntroduceHandlerBase.findExpression(context.getStatements()[0]);
GrVariable var = GrIntroduceHandlerBase.findVariable(context.getStatements()[0]);
final PsiType type = TypesUtil.unboxPrimitiveTypeWrapper(var == null ? expr.getType() : var.getType());
return new GrIntroduceExpressionSettingsImpl(context, "anObject", declareFinal, toRemove, generateDelegate, replaceFieldsWithGetters, expr, var, type);
}
@@ -1,4 +1,4 @@
<caret>def foo(def anObject) {
<caret>def foo(String anObject) {
print(anObject)
}
@@ -1,4 +1,4 @@
def a = {int x, int z, def anObject ->
def a = {int x, int z, int anObject ->
print anObject + x+z
}