diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml
index 221d32a9bb20..61a374a1c9c6 100644
--- a/plugins/groovy/src/META-INF/plugin.xml
+++ b/plugins/groovy/src/META-INF/plugin.xml
@@ -1086,6 +1086,11 @@
+
+
{0} cannot be
variable.is.accessed.for.writing=Variable ''{0}'' is accessed for writing
introduce.closure.parameter.elements.header=Adding parameter to a closure
extract.closure.title=Extract closure
+cannot.process.usage.in.language.{0}=Cannot process usage in {0}
+you.cannot.pass.as.parameter.0.because.you.remove.1.from.base.method=You cannot pass ''{0}'' as parameter because you remove ''{1}'' from the method. You should deselect "Remove parameter ''{0}'' no longer used" or deselect parameter ''{1}'' in the parameter table.
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ExtractHandlerBase.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ExtractHandlerBase.java
index 3f6a56b4b6e6..44060186614d 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ExtractHandlerBase.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ExtractHandlerBase.java
@@ -34,9 +34,13 @@ import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils;
import org.jetbrains.plugins.groovy.lang.psi.GrControlFlowOwner;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrIfStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrReturnStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrIndexProperty;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrMemberOwner;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
import org.jetbrains.plugins.groovy.lang.psi.api.util.GrStatementOwner;
@@ -45,15 +49,17 @@ import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.ReachingDefin
import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.VariableInfo;
import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringBundle;
import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringUtil;
+import org.jetbrains.plugins.groovy.refactoring.inline.GroovyInlineMethodUtil;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.Set;
/**
* @author Max Medvedev
*/
-public abstract class ExtractHandlerBase implements RefactoringActionHandler {
+public abstract class ExtractHandlerBase implements RefactoringActionHandler {
private static final Logger LOG = Logger.getInstance(ExtractHandlerBase.class);
public void invokeOnEditor(Project project, Editor editor, PsiFile file, int start, int end) throws ExtractException {
@@ -68,12 +74,12 @@ public abstract class ExtractHandlerBase i
SelectionModel selectionModel = editor.getSelectionModel();
PsiDocumentManager.getInstance(project).commitAllDocuments();
- PsiElement[] elements = ExtractUtil.getElementsInOffset(file, start, end);
+ PsiElement[] elements = getElementsInOffset(file, start, end);
if (elements.length == 1 && elements[0] instanceof GrExpression) {
selectionModel.setSelection(start, elements[0].getTextRange().getEndOffset());
}
- GrStatement[] statements = ExtractUtil.getStatementsByElements(elements);
+ GrStatement[] statements = getStatementsByElements(elements);
if (statements.length == 0) {
String message =
@@ -90,8 +96,8 @@ public abstract class ExtractHandlerBase i
}
GrStatement statement0 = statements[0];
- GrMemberOwner owner = ExtractUtil.getMemberOwner(statement0);
- GrStatementOwner declarationOwner = ExtractUtil.getDeclarationOwner(statement0);
+ GrMemberOwner owner = getMemberOwner(statement0);
+ GrStatementOwner declarationOwner = getDeclarationOwner(statement0);
if (owner == null || declarationOwner == null && !ExtractUtil.isSingleExpression(statements)) {
String message =
RefactoringBundle.getCannotRefactorMessage(GroovyRefactoringBundle.message("refactoring.is.not.supported.in.the.current.context"));
@@ -145,7 +151,7 @@ public abstract class ExtractHandlerBase i
boolean hasReturns = returnStatements.size() > 0;
List returnStatementsCopy = new ArrayList(returnStatements.size());
returnStatementsCopy.addAll(returnStatements);
- boolean isReturnStatement = ExtractUtil.isReturnStatement(statements[statements.length - 1], returnStatementsCopy);
+ boolean isReturnStatement = isReturnStatement(statements[statements.length - 1], returnStatementsCopy);
boolean isLastStatementOfMethod = isLastStatementOfMethodOrClosure(statements);
if (hasReturns && !isLastStatementOfMethod && !isReturnStatement || hasInterruptingStatements) {
String message = GroovyRefactoringBundle.message("refactoring.is.not.supported.when.return.statement.interrupts.the.execution.flow");
@@ -154,10 +160,8 @@ public abstract class ExtractHandlerBase i
InitialInfo info = new InitialInfo(inputInfos, outputInfos, elements, statements, owner, returnStatements);
- InfoHelper helper = getSettings(info);
- if (helper == null) return;
- performRefactoring(helper, owner, declarationOwner, editor, statement0);
+ performRefactoring(info, owner, declarationOwner, editor, statement0);
}
private static boolean isLastStatementOfMethodOrClosure(GrStatement[] statements) {
@@ -175,12 +179,64 @@ public abstract class ExtractHandlerBase i
return statement0.getManager().areElementsEquivalent(lastFromBlock, lastStatement);
}
- @Nullable
- public abstract InfoHelper getSettings(@NotNull final InitialInfo initialInfo);
-
- public abstract void performRefactoring(@NotNull final InfoHelper helper,
+ public abstract void performRefactoring(@NotNull final InitialInfo initialInfo,
@NotNull final GrMemberOwner owner,
final GrStatementOwner declarationOwner,
final Editor editor,
final PsiElement startElement);
+
+ private static GrStatement[] getStatementsByElements(PsiElement[] elements) {
+ ArrayList statementList = new ArrayList();
+ for (PsiElement element : elements) {
+ if (element instanceof GrStatement) {
+ statementList.add(((GrStatement) element));
+ }
+ }
+ return statementList.toArray(new GrStatement[statementList.size()]);
+ }
+
+ private static PsiElement[] getElementsInOffset(PsiFile file, int startOffset, int endOffset) {
+ PsiElement[] elements;
+ GrExpression expr = GroovyRefactoringUtil.findElementInRange(file, startOffset, endOffset, GrExpression.class);
+
+ 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 = GroovyRefactoringUtil.findStatementsInRange(file, startOffset, endOffset, true);
+ }
+ return elements;
+ }
+
+ @Nullable
+ private static GrMemberOwner getMemberOwner(GrStatement statement) {
+ PsiElement parent = statement.getParent();
+ while (parent != null && !(parent instanceof GrMemberOwner)) {
+ if (parent instanceof GroovyFileBase) return (GrMemberOwner) ((GroovyFileBase) parent).getScriptClass();
+ parent = parent.getParent();
+ }
+ return parent != null ? ((GrMemberOwner) parent) : null;
+ }
+
+ @Nullable
+ private static GrStatementOwner getDeclarationOwner(GrStatement statement) {
+ PsiElement parent = statement.getParent();
+ return parent instanceof GrStatementOwner ? ((GrStatementOwner) parent) : null;
+ }
+
+ private static boolean isReturnStatement(GrStatement statement, Collection returnStatements) {
+ if (statement instanceof GrReturnStatement) return true;
+ if (statement instanceof GrIfStatement) {
+ boolean checked = GroovyInlineMethodUtil.checkTailIfStatement(((GrIfStatement)statement), returnStatements);
+ return checked & returnStatements.size() == 0;
+
+ }
+ if (statement instanceof GrExpression) {
+ return returnStatements.contains(statement);
+ }
+ return false;
+ }
}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ExtractInfoHelper.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ExtractInfoHelper.java
index 2da2a3ddc24c..dca341c1c16e 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ExtractInfoHelper.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ExtractInfoHelper.java
@@ -20,7 +20,6 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement;
-import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrMemberOwner;
import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.VariableInfo;
/**
@@ -34,7 +33,7 @@ public interface ExtractInfoHelper {
ParameterInfo[] getParameterInfos();
@NotNull
- VariableInfo[] getOutputNames();
+ VariableInfo[] getOutputVariableInfos();
@NotNull
String[] getArgumentNames();
@@ -48,6 +47,7 @@ public interface ExtractInfoHelper {
@NotNull
GrStatement[] getStatements();
- @NotNull
- GrMemberOwner getOwner();
+ boolean hasReturnValue();
+
+ String getName();
}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ExtractInfoHelperBase.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ExtractInfoHelperBase.java
index c253ceb53596..bc2bfc7e8a90 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ExtractInfoHelperBase.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ExtractInfoHelperBase.java
@@ -20,7 +20,6 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement;
-import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrMemberOwner;
import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.VariableInfo;
import java.util.Collection;
@@ -30,7 +29,7 @@ import java.util.Map;
/**
* @author Max Medvedev
*/
-public class ExtractInfoHelperBase implements ExtractInfoHelper {
+public abstract class ExtractInfoHelperBase implements ExtractInfoHelper {
protected final InitialInfo myInitialInfo;
protected final Map myInputNamesMap;
@@ -66,8 +65,8 @@ public class ExtractInfoHelperBase implements ExtractInfoHelper {
@Override
@NotNull
- public VariableInfo[] getOutputNames() {
- return myInitialInfo.getOutputNames();
+ public VariableInfo[] getOutputVariableInfos() {
+ return myInitialInfo.getOutputVariableInfos();
}
/**
@@ -107,12 +106,6 @@ public class ExtractInfoHelperBase implements ExtractInfoHelper {
return myInitialInfo.getStatements();
}
- @Override
- @NotNull
- public GrMemberOwner getOwner() {
- return myInitialInfo.getOwner();
- }
-
public boolean hasReturnValue() {
return myInitialInfo.hasReturnValue();
}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ExtractUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ExtractUtil.java
index 26db5d4ee16e..309578d656a4 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ExtractUtil.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/ExtractUtil.java
@@ -16,46 +16,33 @@
package org.jetbrains.plugins.groovy.refactoring.extract;
+import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
-import com.intellij.refactoring.ui.ConflictsDialog;
-import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.HashMap;
-import gnu.trove.TObjectHashingStrategy;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import org.jetbrains.plugins.groovy.intentions.utils.DuplicatesUtil;
-import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
-import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase;
-import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
+import org.jetbrains.plugins.groovy.lang.GrReferenceAdjuster;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
-import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrIfStatement;
+import org.jetbrains.plugins.groovy.lang.psi.GroovyRecursiveElementVisitor;
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.GrVariableDeclaration;
-import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock;
-import org.jetbrains.plugins.groovy.lang.psi.api.statements.branch.GrReturnStatement;
-import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrAssignmentExpression;
-import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
-import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
-import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrIndexProperty;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression;
-import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrMemberOwner;
-import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
+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.api.util.GrStatementOwner;
import org.jetbrains.plugins.groovy.lang.psi.api.util.GrVariableDeclarationOwner;
import org.jetbrains.plugins.groovy.lang.psi.dataFlow.reachingDefs.VariableInfo;
+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.lang.psi.impl.synthetic.GroovyScriptClass;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
-import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringBundle;
import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringUtil;
import org.jetbrains.plugins.groovy.refactoring.extract.method.ExtractMethodInfoHelper;
-import org.jetbrains.plugins.groovy.refactoring.inline.GroovyInlineMethodUtil;
import java.util.*;
@@ -63,44 +50,45 @@ import java.util.*;
* @author ilyas
*/
public class ExtractUtil {
+ private static final Logger LOG = Logger.getInstance(ExtractUtil.class);
private ExtractUtil() {
}
- @Nullable
- public static PsiElement calculateAnchorToInsertBefore(GrMemberOwner owner, PsiElement startElement) {
- while (startElement != null && !isEnclosingDefinition(owner, startElement)) {
- if (startElement.getParent() instanceof GroovyFile) {
- return startElement.getNextSibling();
- }
- startElement = startElement.getParent();
- PsiElement parent = startElement.getParent();
- if (parent instanceof GroovyFile && ((GroovyFile) parent).getScriptClass() == owner) {
- return startElement.getNextSibling();
+ public static GrStatement replaceStatement(GrStatementOwner declarationOwner, ExtractInfoHelper helper) {
+ GrStatement realStatement;
+ if (declarationOwner != null && !isSingleExpression(helper.getStatements())) {
+ // Replace set of statements
+ final GrStatement[] newStatement = createResultStatement(helper);
+ // add call statement
+ final GrStatement[] statements = helper.getStatements();
+ LOG.assertTrue(statements.length > 0);
+ realStatement = null;
+ for (GrStatement statement : newStatement) {
+ realStatement = declarationOwner.addStatementBefore(statement, statements[0]);
}
+ LOG.assertTrue(realStatement != null);
+ // remove old statements
+ removeOldStatements(declarationOwner, helper);
+ PsiImplUtil.removeNewLineAfter(realStatement);
}
- return startElement == null ? null : startElement.getNextSibling();
- }
-
- private static boolean isEnclosingDefinition(GrMemberOwner owner, PsiElement startElement) {
- if (owner instanceof GrTypeDefinition) {
- GrTypeDefinition definition = (GrTypeDefinition) owner;
- return startElement.getParent() == definition.getBody();
+ else {
+ // Expression call replace
+ GrExpression methodCall = createMethodCall(helper);
+ GrExpression oldExpr = (GrExpression)helper.getStatements()[0];
+ realStatement = oldExpr.replaceWithExpression(methodCall, true);
}
- return false;
- }
-
- public enum MethodAccessQualifier {
- PUBLIC, PRIVATE, PROTECTED
+ GrReferenceAdjuster.shortenReferences(realStatement);
+ return realStatement;
}
@NotNull
- public static GrStatement[] createResultStatement(ExtractMethodInfoHelper helper, @NotNull String methodName) {
- VariableInfo[] outputVars = helper.getOutputNames();
+ private static GrStatement[] createResultStatement(ExtractInfoHelper helper) {
+ VariableInfo[] outputVars = helper.getOutputVariableInfos();
PsiType type = helper.getOutputType();
GrStatement[] statements = helper.getStatements();
- GrMethodCallExpression callExpression = createMethodCallByHelper(methodName, helper);
+ GrMethodCallExpression callExpression = createMethodCall(helper);
if ((outputVars.length == 0 || PsiType.VOID.equals(type)) && !helper.hasReturnValue()) return new GrStatement[]{callExpression};
GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(helper.getProject());
@@ -108,7 +96,7 @@ public class ExtractUtil {
return new GrStatement[]{factory.createStatementFromText("return " + callExpression.getText())};
}
- assert outputVars.length > 0;
+ LOG.assertTrue(outputVars.length > 0);
final List mustAdd = mustAddVariableDeclaration(statements, outputVars);
if (mustAdd.size() == 0) {
@@ -158,7 +146,7 @@ public class ExtractUtil {
return diffTypes.size() > 1;
}
- private static GrStatement createAssignment(VariableInfo[] infos, GrMethodCallExpression callExpression, ExtractMethodInfoHelper helper) {
+ private static GrStatement createAssignment(VariableInfo[] infos, GrMethodCallExpression callExpression, ExtractInfoHelper helper) {
StringBuilder text = new StringBuilder();
if (infos.length > 1) text.append('(');
for (VariableInfo info : infos) {
@@ -174,46 +162,7 @@ public class ExtractUtil {
return GroovyPsiElementFactory.getInstance(helper.getProject()).createExpressionFromText(text.toString());
}
- public static boolean validateMethod(GrMethod method, ExtractMethodInfoHelper helper) {
- ArrayList conflicts = new ArrayList();
- GrMemberOwner owner = helper.getOwner();
- PsiMethod[] methods = ArrayUtil.mergeArrays(owner.getAllMethods(), new PsiMethod[]{method}, PsiMethod.ARRAY_FACTORY);
- final Map> map = DuplicatesUtil.factorDuplicates(methods, new TObjectHashingStrategy() {
- public int computeHashCode(PsiMethod method) {
- return method.getSignature(PsiSubstitutor.EMPTY).hashCode();
- }
-
- public boolean equals(PsiMethod method1, PsiMethod method2) {
- return method1.getSignature(PsiSubstitutor.EMPTY).equals(method2.getSignature(PsiSubstitutor.EMPTY));
- }
- });
-
- List list = map.get(method);
- if (list == null) return true;
- for (PsiMethod psiMethod : list) {
- if (psiMethod != method) {
- PsiClass containingClass = psiMethod.getContainingClass();
- if (containingClass == null) return true;
- String message = containingClass instanceof GroovyScriptClass ?
- GroovyRefactoringBundle.message("method.is.already.defined.in.script", GroovyRefactoringUtil.getMethodSignature(method),
- CommonRefactoringUtil.htmlEmphasize(containingClass.getQualifiedName())) :
- GroovyRefactoringBundle.message("method.is.already.defined.in.class", GroovyRefactoringUtil.getMethodSignature(method),
- CommonRefactoringUtil.htmlEmphasize(containingClass.getQualifiedName()));
- conflicts.add(message);
- }
- }
-
- return conflicts.size() <= 0 || reportConflicts(conflicts, helper.getProject());
- }
-
- static boolean reportConflicts(final ArrayList conflicts, final Project project) {
- ConflictsDialog conflictsDialog = new ConflictsDialog(project, conflicts);
- conflictsDialog.show();
- return conflictsDialog.isOK();
- }
-
-
- public static void removeOldStatements(GrStatementOwner owner, ExtractMethodInfoHelper helper) throws IncorrectOperationException {
+ private static void removeOldStatements(GrStatementOwner owner, ExtractInfoHelper helper) throws IncorrectOperationException {
owner.removeElements(helper.getInnerElements());
}
@@ -247,49 +196,35 @@ public class ExtractUtil {
return result;
}
- private static boolean containVariableDeclaration(@NotNull GrStatement[] statements, @NotNull String varName) {
- GroovyPsiElement element = ResolveUtil.resolveProperty(statements[0], varName);
- if (element == null) return false;
- for (GrStatement statement : statements) {
- if (statement.getTextRange().contains(element.getTextRange())) {
- return true;
- }
- }
- return false;
- }
+ private static Collection collectUsedLocalVarsOrParamsDeclaredOutside(GrStatement[] statements) {
+ final Collection result = new HashSet();
- public static void renameParameterOccurrences(GrMethod method, ExtractMethodInfoHelper helper) throws IncorrectOperationException {
- GrOpenBlock block = method.getBlock();
- if (block == null) return;
- GrStatement[] statements = block.getStatements();
-
- final GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(helper.getProject());
- for (ParameterInfo info : helper.getParameterInfos()) {
- final String oldName = info.getOldName();
- final String newName = info.getName();
- final ArrayList result = new ArrayList();
- if (!oldName.equals(newName)) {
- for (final GrStatement statement : statements) {
- statement.accept(new PsiRecursiveElementVisitor() {
- public void visitElement(final PsiElement element) {
- super.visitElement(element);
- if (element instanceof GrReferenceExpression) {
- GrReferenceExpression expr = (GrReferenceExpression) element;
- if (!expr.isQualified() && oldName.equals(expr.getName())) {
- result.add(expr);
- }
- }
- }
- });
- for (GrExpression expr : result) {
- expr.replaceWithExpression(factory.createExpressionFromText(newName), false);
+ final int start = statements[0].getTextRange().getStartOffset();
+ final int end = statements[statements.length - 1].getTextRange().getEndOffset();
+
+ final GroovyRecursiveElementVisitor visitor = new GroovyRecursiveElementVisitor() {
+ @Override
+ public void visitReferenceExpression(GrReferenceExpression ref) {
+ final PsiElement resolved = ref.resolve();
+ if ((resolved instanceof GrParameter ||
+ resolved instanceof GrVariable && GroovyRefactoringUtil.isLocalVariable((GrVariable)resolved)) && resolved.isPhysical()) {
+ final int offset = resolved.getTextRange().getStartOffset();
+ //var is declared outside of selected code
+ if (offset < start || end <= offset) {
+ result.add((GrVariable)resolved);
}
}
}
+ };
+
+ for (GrStatement statement : statements) {
+ statement.accept(visitor);
}
+
+ return result;
}
- public static GrMethod createMethodByHelper(@NotNull String name, ExtractMethodInfoHelper helper) {
+ public static GrMethod createMethod(ExtractMethodInfoHelper helper) {
StringBuilder buffer = new StringBuilder();
//Add signature
@@ -300,7 +235,7 @@ public class ExtractUtil {
String typeText = getTypeString(helper, false, modifier);
buffer.append(modifier);
buffer.append(typeText);
- buffer.append(name);
+ buffer.append(helper.getName());
buffer.append("(");
for (String param : getParameterString(helper, true)) {
buffer.append(param);
@@ -308,27 +243,47 @@ public class ExtractUtil {
buffer.append(") { \n");
GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(helper.getProject());
- VariableInfo[] outputInfos = helper.getOutputNames();
+ generateBody(helper, type == PsiType.VOID, buffer);
+
+ buffer.append("\n}");
+
+ String methodText = buffer.toString();
+ GrMethod method = factory.createMethodFromText(methodText);
+ LOG.assertTrue(method != null);
+ return method;
+ }
+
+ public static void generateBody(ExtractInfoHelper helper, boolean isVoid, StringBuilder buffer) {
+ VariableInfo[] outputInfos = helper.getOutputVariableInfos();
ParameterInfo[] infos = helper.getParameterInfos();
- boolean[] outputIsParameter = new boolean[outputInfos.length];
- for (int i = 0; i < outputInfos.length; i++) {
- for (ParameterInfo info : infos) {
- if (outputInfos[i].getName().equals(info.getOldName())) {
- outputIsParameter[i] = true;
- }
- }
+
+ Set declaredVars = new HashSet();
+ for (ParameterInfo info : infos) {
+ declaredVars.add(info.getName());
}
- final Set mustAdd = new HashSet(mustAddVariableDeclaration(helper.getStatements(), outputInfos));
+ for (VariableInfo info : mustAddVariableDeclaration(helper.getStatements(), outputInfos)) {
+ declaredVars.add(info.getName());
+ }
List genDecl = new ArrayList();
- for (int i = 0; i < outputInfos.length; i++) {
- VariableInfo info = outputInfos[i];
- if (type != PsiType.VOID && !outputIsParameter[i] &&
- !mustAdd.contains(info) &&
- !containVariableDeclaration(helper.getStatements(), info.getName())) {
- genDecl.add(info);
+ final Collection outside = collectUsedLocalVarsOrParamsDeclaredOutside(helper.getStatements());
+
+ for (final GrVariable variable : outside) {
+ if (!declaredVars.contains(variable.getName())) {
+ genDecl.add(new VariableInfo() {
+ @NotNull
+ @Override
+ public String getName() {
+ return variable.getName();
+ }
+
+ @Override
+ public PsiType getType() {
+ return variable.getDeclaredType();
+ }
+ });
}
}
final List statements = generateVarDeclarations(genDecl, helper.getProject(), null);
@@ -341,7 +296,7 @@ public class ExtractUtil {
buffer.append(element.getText());
}
//append return statement
- if (type != PsiType.VOID && outputInfos.length > 0) {
+ if (!isVoid && outputInfos.length > 0) {
buffer.append("\n return ");
if (outputInfos.length > 1) buffer.append('[');
for (VariableInfo info : outputInfos) {
@@ -353,15 +308,29 @@ public class ExtractUtil {
}
else {
GrExpression expr = (GrExpression)PsiUtil.skipParentheses(helper.getStatements()[0], false);
- buffer.append(PsiType.VOID.equals(type) ? "" : "return ").append(expr != null ? expr.getText() : "");
+ boolean addReturn = !isVoid && expr != null && expr.getType() != null && expr.getType() != PsiType.VOID;
+ if (addReturn) {
+ buffer.append("return ");
+ if (expr instanceof GrApplicationStatement) {
+ final GrApplicationStatement appStatement = (GrApplicationStatement)expr;
+
+ buffer.append(appStatement.getInvokedExpression().getText());
+ buffer.append('(');
+
+ final GrCommandArgumentList argList = appStatement.getArgumentList();
+ if (argList != null) {
+ buffer.append(argList.getText());
+ }
+ buffer.append(')');
+ }
+ else {
+ buffer.append(expr.getText());
+ }
+ }
+ else {
+ buffer.append(expr != null ? expr.getText() : "");
+ }
}
-
- buffer.append("\n}");
-
- String methodText = buffer.toString();
- GrMethod method = factory.createMethodFromText(methodText);
- assert method != null;
- return method;
}
public static String[] getParameterString(ExtractInfoHelper helper, boolean useCanonicalText) {
@@ -412,56 +381,14 @@ public class ExtractUtil {
return typeText;
}
- public static GrStatement[] getStatementsByElements(PsiElement[] elements) {
- ArrayList statementList = new ArrayList();
- for (PsiElement element : elements) {
- if (element instanceof GrStatement) {
- statementList.add(((GrStatement) element));
- }
- }
- return statementList.toArray(new GrStatement[statementList.size()]);
- }
-
- public static PsiElement[] getElementsInOffset(PsiFile file, int startOffset, int endOffset) {
- PsiElement[] elements;
- GrExpression expr = GroovyRefactoringUtil.findElementInRange(file, startOffset, endOffset, GrExpression.class);
-
- 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 = GroovyRefactoringUtil.findStatementsInRange(file, startOffset, endOffset, true);
- }
- return elements;
- }
-
- @Nullable
- public static GrMemberOwner getMemberOwner(GrStatement statement) {
- PsiElement parent = statement.getParent();
- while (parent != null && !(parent instanceof GrMemberOwner)) {
- if (parent instanceof GroovyFileBase) return (GrMemberOwner) ((GroovyFileBase) parent).getScriptClass();
- parent = parent.getParent();
- }
- return parent != null ? ((GrMemberOwner) parent) : null;
- }
-
- @Nullable
- public static GrStatementOwner getDeclarationOwner(GrStatement statement) {
- PsiElement parent = statement.getParent();
- return parent instanceof GrStatementOwner ? ((GrStatementOwner) parent) : null;
- }
-
public static boolean isSingleExpression(GrStatement[] statements) {
return statements.length == 1 && statements[0] instanceof GrExpression &&
!(statements[0].getParent() instanceof GrVariableDeclarationOwner && statements[0] instanceof GrAssignmentExpression);
}
- public static GrMethodCallExpression createMethodCallByHelper(@NotNull String name, ExtractMethodInfoHelper helper) {
+ private static GrMethodCallExpression createMethodCall(ExtractInfoHelper helper) {
StringBuilder buffer = new StringBuilder();
- buffer.append(name).append("(");
+ buffer.append(helper.getName()).append("(");
int number = 0;
for (ParameterInfo info : helper.getParameterInfos()) {
if (info.passAsParameter()) number++;
@@ -482,7 +409,7 @@ public class ExtractUtil {
String callText = buffer.toString();
GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(helper.getProject());
GrExpression expr = factory.createExpressionFromText(callText);
- assert expr instanceof GrMethodCallExpression;
+ LOG.assertTrue(expr instanceof GrMethodCallExpression, callText);
return ((GrMethodCallExpression) expr);
}
@@ -505,35 +432,10 @@ public class ExtractUtil {
return statement.getTextOffset();
}
- public static boolean canBeStatic(GrStatement statement) {
- PsiElement parent = statement.getParent();
- while (parent != null && !(parent instanceof PsiFile)) {
- if (parent instanceof GrMethod) {
- return ((GrMethod) parent).hasModifierProperty(PsiModifier.STATIC);
- }
- parent = parent.getParent();
- }
- return false;
- }
-
public static String getModifierString(ExtractMethodInfoHelper helper) {
String visibility = helper.getVisibility();
- assert visibility != null && visibility.length() > 0;
+ LOG.assertTrue(visibility != null && visibility.length() > 0);
visibility = visibility.equals(PsiModifier.PUBLIC) ? "" : visibility + " ";
return visibility + (helper.isStatic() ? "static " : "");
}
-
- public static boolean isReturnStatement(GrStatement statement, Collection returnStatements) {
- if (statement instanceof GrReturnStatement) return true;
- if (statement instanceof GrIfStatement) {
- boolean checked = GroovyInlineMethodUtil.checkTailIfStatement(((GrIfStatement) statement), returnStatements);
- return checked & returnStatements.size() == 0;
-
- }
- if (statement instanceof GrExpression) {
- return returnStatements.contains(statement);
- }
- return false;
- }
-
}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/InitialInfo.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/InitialInfo.java
index f25d36007bb9..569c4d44117f 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/InitialInfo.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/InitialInfo.java
@@ -42,7 +42,6 @@ public class InitialInfo implements ExtractInfoHelper {
private final ParameterInfo[] myParameterInfos;
private final VariableInfo[] myOutputNames;
private final PsiType myOutputType;
- private final GrMemberOwner myTargetClass;
private final PsiElement[] myInnerElements;
private final Project myProject;
private final GrStatement[] myStatements;
@@ -57,7 +56,6 @@ public class InitialInfo implements ExtractInfoHelper {
ArrayList returnStatements) {
myInnerElements = innerElements;
myStatements = statements;
- myTargetClass = targetClass;
myOutputNames = outputInfos;
myHasReturnValue = ContainerUtil.find(returnStatements, new Condition() {
@@ -94,7 +92,7 @@ public class InitialInfo implements ExtractInfoHelper {
outputType = outputInfos[0].getType();
}
else {
- outputType = JavaPsiFacade.getElementFactory(myProject).createTypeFromText(CommonClassNames.JAVA_UTIL_LIST, myTargetClass);
+ outputType = JavaPsiFacade.getElementFactory(myProject).createTypeFromText(CommonClassNames.JAVA_UTIL_LIST, myStatements[0]);
}
}
else if (ExtractUtil.isSingleExpression(statements)) {
@@ -137,7 +135,7 @@ public class InitialInfo implements ExtractInfoHelper {
@Override
@NotNull
- public VariableInfo[] getOutputNames() {
+ public VariableInfo[] getOutputVariableInfos() {
return myOutputNames;
}
@@ -170,13 +168,12 @@ public class InitialInfo implements ExtractInfoHelper {
return myStatements;
}
- @Override
- @NotNull
- public GrMemberOwner getOwner() {
- return myTargetClass;
- }
-
public boolean hasReturnValue() {
return myHasReturnValue;
}
+
+ @Override
+ public String getName() {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/closure/ExtractClosureAction.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/closure/ExtractClosureAction.java
new file mode 100644
index 000000000000..b77ed8198775
--- /dev/null
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/closure/ExtractClosureAction.java
@@ -0,0 +1,36 @@
+/*
+ * 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.lang.refactoring.RefactoringSupportProvider;
+import com.intellij.refactoring.RefactoringActionHandler;
+import com.intellij.refactoring.actions.BasePlatformRefactoringAction;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author Max Medvedev
+ */
+public class ExtractClosureAction extends BasePlatformRefactoringAction {
+ @Override
+ protected RefactoringActionHandler getRefactoringHandler(@NotNull RefactoringSupportProvider provider) {
+ return new ExtractClosureHandler();
+ }
+
+ @Override
+ protected boolean isAvailableInEditorOnly() {
+ return true;
+ }
+}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/closure/ExtractClosureDialog.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/closure/ExtractClosureDialog.java
new file mode 100644
index 000000000000..0c462fc02ef3
--- /dev/null
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/closure/ExtractClosureDialog.java
@@ -0,0 +1,263 @@
+/*
+ * 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.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.JavaRefactoringSettings;
+import com.intellij.ui.EditorTextField;
+import com.intellij.ui.IdeBorderFactory;
+import com.intellij.ui.components.JBCheckBox;
+import com.intellij.ui.components.JBLabel;
+import com.intellij.util.ui.UIUtil;
+import gnu.trove.TIntArrayList;
+import gnu.trove.TObjectIntHashMap;
+import gnu.trove.TObjectIntProcedure;
+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.ui.GrMethodSignatureComponent;
+
+import javax.swing.*;
+import java.awt.*;
+
+/**
+ * @author Max Medvedev
+ */
+public class ExtractClosureDialog extends DialogWrapper {
+
+ private final ParameterTablePanel myTable;
+ private final GrMethodSignatureComponent mySignature;
+ private final EditorTextField myNameField;
+
+ private final ExtractClosureHelper myHelper;
+ private final JBCheckBox myFinalCB;
+ private final JBCheckBox myGenerateDelegateCB;
+
+ TObjectIntHashMap toRemoveCBs;
+ private final InitialInfo myInitialInfo;
+
+ public ExtractClosureDialog(InitialInfo initialInfo, GrParametersOwner owner, PsiElement toSearchFor) {
+ super(initialInfo.getProject());
+ myInitialInfo = initialInfo;
+
+ myHelper = new ExtractClosureHelper(initialInfo, owner, toSearchFor, "", false);
+
+ setTitle(ExtractClosureHandler.EXTRACT_CLOSURE);
+
+ myTable = new ParameterTablePanel() {
+ @Override
+ protected void updateSignature() {
+ ExtractClosureDialog.this.updateSignature();
+ }
+
+ @Override
+ protected void doEnterAction() {
+ clickDefaultButton();
+ }
+
+ @Override
+ protected void doCancelAction() {
+ ExtractClosureDialog.this.doCancelAction();
+ }
+ };
+
+ mySignature = new GrMethodSignatureComponent("", initialInfo.getProject());
+ myNameField = new EditorTextField("", initialInfo.getProject(), GroovyFileType.GROOVY_FILE_TYPE);
+ myFinalCB = new JBCheckBox(UIUtil.replaceMnemonicAmpersand("Declare &final"));
+ myFinalCB.setFocusable(false);
+ myGenerateDelegateCB = new JBCheckBox(UIUtil.replaceMnemonicAmpersand("De&legate via overloading method"));
+ myGenerateDelegateCB.setFocusable(false);
+
+ TObjectIntHashMap parametersToRemove = findParametersToRemove(myHelper);
+ toRemoveCBs = new TObjectIntHashMap(parametersToRemove.size());
+ for (Object p : parametersToRemove.keys()) {
+ JBCheckBox cb = new JBCheckBox(GroovyRefactoringBundle.message("remove.parameter.0.no.longer.used", ((GrParameter)p).getName()));
+ cb.setFocusable(false);
+ cb.setSelected(false);
+ toRemoveCBs.put(cb, parametersToRemove.get((GrParameter)p));
+ }
+
+ init();
+ }
+
+ @Override
+ protected ValidationInfo doValidate() {
+ final String text = myNameField.getText().trim();
+ if (!StringUtil.isJavaIdentifier(text)) {
+ return new ValidationInfo(GroovyRefactoringBundle.message("name.is.wrong", text), myNameField);
+ }
+
+ final Ref info = new Ref();
+ toRemoveCBs.forEachEntry(new TObjectIntProcedure() {
+ @Override
+ public boolean execute(JBCheckBox checkbox, int index) {
+ if (!checkbox.isSelected()) return true;
+
+ final ParameterInfo param = myHelper.getParameterInfos()[index];
+ if (!param.passAsParameter()) return true;
+
+ final ParameterInfo initialParam = myInitialInfo.getParameterInfos()[index];
+ final String message = GroovyRefactoringBundle.message("you.cannot.pass.as.parameter.0.because.you.remove.1.from.base.method",
+ param.getName(), initialParam.getName());
+ info.set(new ValidationInfo(message));
+ return false;
+ }
+ });
+ return info.get();
+ }
+
+ private void updateSignature() {
+ StringBuilder b = new StringBuilder();
+ b.append("{ ");
+ String[] params = ExtractUtil.getParameterString(myHelper, false);
+ for (int i = 0; i < params.length; i++) {
+ if (i > 0) {
+ b.append(" ");
+ }
+ b.append(params[i]);
+ b.append('\n');
+ }
+ b.append(" ->\n}");
+ mySignature.setSignature(b.toString());
+ }
+
+ @Override
+ public JComponent getPreferredFocusedComponent() {
+ return myNameField;
+ }
+
+ @Override
+ protected void init() {
+ super.init();
+
+ myTable.init(myHelper);
+
+ final JavaRefactoringSettings refactoringSettings = JavaRefactoringSettings.getInstance();
+ final Boolean settingsFinals = refactoringSettings.INTRODUCE_PARAMETER_CREATE_FINALS;
+ myFinalCB.setSelected(settingsFinals == null ?
+ CodeStyleSettingsManager.getSettings(myHelper.getProject()).GENERATE_FINAL_PARAMETERS :
+ settingsFinals.booleanValue());
+ myGenerateDelegateCB.setSelected(false);
+ updateSignature();
+ }
+
+ @Override
+ protected JComponent createNorthPanel() {
+ final JPanel panel = new JPanel(new BorderLayout());
+ final JBLabel nameLabel = new JBLabel();
+ panel.add(nameLabel, BorderLayout.NORTH);
+ panel.add(myNameField, BorderLayout.CENTER);
+ nameLabel.setText(UIUtil.replaceMnemonicAmpersand("Parameter &name:"));
+ nameLabel.setLabelFor(myNameField);
+
+ final JPanel checkBoxPanel = new JPanel();
+ checkBoxPanel.setLayout(new BoxLayout(checkBoxPanel, BoxLayout.Y_AXIS));
+
+ checkBoxPanel.add(myFinalCB);
+ checkBoxPanel.add(myGenerateDelegateCB);
+ for (Object cb : toRemoveCBs.keys()) {
+ checkBoxPanel.add((Component)cb);
+ }
+ panel.add(checkBoxPanel, BorderLayout.SOUTH);
+ return panel;
+ }
+
+ @Override
+ protected JComponent createCenterPanel() {
+ final JPanel signaturePanel = new JPanel(new BorderLayout());
+ signaturePanel.setBorder(
+ IdeBorderFactory.createTitledBorder(GroovyRefactoringBundle.message("signature.preview.border.title"), false, false, true));
+ signaturePanel.add(mySignature, BorderLayout.CENTER);
+
+ Splitter splitter = new Splitter(true);
+
+ splitter.setFirstComponent(myTable);
+ splitter.setSecondComponent(signaturePanel);
+
+ mySignature.setPreferredSize(new Dimension(500, 100));
+ mySignature.setSize(new Dimension(500, 100));
+
+ splitter.setShowDividerIcon(false);
+ return splitter;
+ }
+
+ @Override
+ protected void doOKAction() {
+ 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());
+
+ TIntArrayList list = new TIntArrayList();
+ for (Object cb : toRemoveCBs.keys()) {
+ final JBCheckBox checkbox = (JBCheckBox)cb;
+ if (checkbox.isSelected()) {
+ list.add(toRemoveCBs.get(checkbox));
+ }
+ }
+ myHelper.setToRemove(list);
+ super.doOKAction();
+ }
+
+ public ExtractClosureHelper getHelper() {
+ return myHelper;
+ }
+
+ private static TObjectIntHashMap findParametersToRemove(ExtractClosureHelper helper) {
+ final TObjectIntHashMap result = new TObjectIntHashMap();
+
+ 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;
+ }
+}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/closure/ExtractClosureFromClosureProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/closure/ExtractClosureFromClosureProcessor.java
new file mode 100644
index 000000000000..ca8bf33e1253
--- /dev/null
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/closure/ExtractClosureFromClosureProcessor.java
@@ -0,0 +1,79 @@
+/*
+ * 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.openapi.util.Ref;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiReference;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.search.searches.ReferencesSearch;
+import com.intellij.refactoring.introduceParameter.ExternalUsageInfo;
+import com.intellij.usageView.UsageInfo;
+import org.jetbrains.annotations.NotNull;
+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 java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Max Medvedev
+ */
+public class ExtractClosureFromClosureProcessor extends ExtractClosureProcessorBase {
+ public ExtractClosureFromClosureProcessor(@NotNull ExtractClosureHelper helper) {
+ super(helper);
+ }
+
+ @Override
+ protected boolean preprocessUsages(Ref refUsages) {
+ //todo
+ return true;
+ }
+
+
+ @Override
+ protected void performRefactoring(UsageInfo[] usages) {
+ //To change body of implemented methods use File | Settings | File Templates. todo
+ }
+
+ @NotNull
+ @Override
+ protected UsageInfo[] findUsages() {
+ final List result = new ArrayList();
+
+ final GrVariable var = (GrVariable)myHelper.getToSearchFor();
+
+ for (PsiReference ref : ReferencesSearch.search(var, GlobalSearchScope.allScope(myHelper.getProject()), true)) {
+ final PsiElement element = ref.getElement();
+ if (element.getLanguage() != GroovyFileType.GROOVY_LANGUAGE) {
+ result.add(new OtherLanguageUsageInfo(ref));
+ continue;
+ }
+
+ final GrCall call = GroovyRefactoringUtil.getCallExpressionByMethodReference(element);
+ if (call == null) continue;
+
+ result.add(new ExternalUsageInfo(element));
+ }
+
+ return result.toArray(new UsageInfo[result.size()]);
+ }
+
+
+}
+
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/closure/ExtractClosureFromMethodProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/closure/ExtractClosureFromMethodProcessor.java
new file mode 100644
index 000000000000..db0266647df2
--- /dev/null
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/closure/ExtractClosureFromMethodProcessor.java
@@ -0,0 +1,270 @@
+/*
+ * 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.openapi.editor.Editor;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Ref;
+import com.intellij.psi.*;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.search.searches.MethodReferencesSearch;
+import com.intellij.psi.search.searches.OverridingMethodsSearch;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.refactoring.IntroduceParameterRefactoring;
+import com.intellij.refactoring.RefactoringBundle;
+import com.intellij.refactoring.introduceParameter.ChangedMethodCallInfo;
+import com.intellij.refactoring.introduceParameter.ExternalUsageInfo;
+import com.intellij.refactoring.introduceParameter.InternalUsageInfo;
+import com.intellij.refactoring.introduceParameter.IntroduceParameterData;
+import com.intellij.refactoring.util.CommonRefactoringUtil;
+import com.intellij.refactoring.util.usageInfo.DefaultConstructorImplicitUsageInfo;
+import com.intellij.refactoring.util.usageInfo.NoConstructorClassUsageInfo;
+import com.intellij.usageView.UsageInfo;
+import com.intellij.usageView.UsageViewUtil;
+import com.intellij.util.containers.MultiMap;
+import gnu.trove.TIntArrayList;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.plugins.groovy.GroovyFileType;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock;
+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.GroovyRefactoringBundle;
+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 java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import static com.intellij.refactoring.introduceParameter.IntroduceParameterUtil.changeMethodSignatureAndResolveFieldConflicts;
+import static com.intellij.refactoring.introduceParameter.IntroduceParameterUtil.processUsages;
+import static org.jetbrains.plugins.groovy.refactoring.introduce.parameter.GroovyIntroduceParameterUtil.*;
+
+/**
+ * @author Max Medvedev
+ */
+public class ExtractClosureFromMethodProcessor extends ExtractClosureProcessorBase {
+
+ private final GrMethod myMethod;
+ private Editor myEditor;
+
+ public ExtractClosureFromMethodProcessor(@NotNull ExtractClosureHelper helper, Editor editor) {
+ super(helper);
+ myEditor = editor;
+ myMethod = (GrMethod)myHelper.getOwner();
+ }
+
+ @Override
+ protected boolean preprocessUsages(Ref refUsages) {
+ UsageInfo[] usagesIn = refUsages.get();
+ MultiMap conflicts = new MultiMap();
+ final GrStatement[] statements = myHelper.getStatements();
+
+ for (GrStatement statement : statements) {
+ detectAccessibilityConflicts(statement, usagesIn, conflicts, false, myProject);
+ }
+
+ for (UsageInfo info : usagesIn) {
+ if (info instanceof OtherLanguageUsageInfo) {
+ conflicts.putValue(info.getElement(), GroovyRefactoringBundle.message("cannot.process.usage.in.language.{0}", CommonRefactoringUtil.htmlEmphasize(info.getElement().getLanguage().getDisplayName())));
+ }
+ }
+
+ if (!myMethod.hasModifierProperty(PsiModifier.PRIVATE)) {
+ final AnySupers anySupers = new AnySupers();
+ for (GrStatement statement : statements) {
+ statement.accept(anySupers);
+ }
+ if (anySupers.isResult()) {
+ for (UsageInfo usageInfo : usagesIn) {
+ if (!(usageInfo.getElement() instanceof PsiMethod) && !(usageInfo instanceof InternalUsageInfo)) {
+ if (!PsiTreeUtil.isAncestor(myMethod.getContainingClass(), usageInfo.getElement(), false)) {
+ conflicts.putValue(statements[0], RefactoringBundle
+ .message("parameter.initializer.contains.0.but.not.all.calls.to.method.are.in.its.class",
+ CommonRefactoringUtil.htmlEmphasize(PsiKeyword.SUPER)));
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return showConflicts(conflicts, usagesIn);
+ }
+
+ @NotNull
+ @Override
+ protected UsageInfo[] findUsages() {
+ List result = new ArrayList();
+
+ final PsiMethod toSearchFor = (PsiMethod)myHelper.getToSearchFor();
+
+ for (PsiReference ref1 : MethodReferencesSearch.search(toSearchFor, GlobalSearchScope.projectScope(myProject), true)) {
+ PsiElement ref = ref1.getElement();
+ if (ref.getLanguage() != GroovyFileType.GROOVY_LANGUAGE) {
+ result.add(new OtherLanguageUsageInfo(ref1));
+ continue;
+ }
+
+ if (ref instanceof PsiMethod && ((PsiMethod)ref).isConstructor()) {
+ DefaultConstructorImplicitUsageInfo implicitUsageInfo =
+ new DefaultConstructorImplicitUsageInfo((PsiMethod)ref, ((PsiMethod)ref).getContainingClass(), toSearchFor);
+ result.add(implicitUsageInfo);
+ }
+ else if (ref instanceof PsiClass) {
+ result.add(new NoConstructorClassUsageInfo((PsiClass)ref));
+ }
+ else if (!PsiTreeUtil.isAncestor(myMethod, ref, false)) {
+ result.add(new ExternalUsageInfo(ref));
+ }
+ else {
+ result.add(new ChangedMethodCallInfo(ref));
+ }
+ }
+
+ Collection overridingMethods = OverridingMethodsSearch.search(toSearchFor, true).findAll();
+
+ for (PsiMethod overridingMethod : overridingMethods) {
+ result.add(new UsageInfo(overridingMethod));
+ }
+
+ final UsageInfo[] usageInfos = result.toArray(new UsageInfo[result.size()]);
+ return UsageViewUtil.removeDuplicatedUsages(usageInfos);
+ }
+
+
+ @Override
+ protected void performRefactoring(UsageInfo[] usages) {
+ final IntroduceParameterData data = new IntroduceParameterDataAdapter();
+
+ processUsages(usages, data);
+
+ final PsiMethod toSearchFor = (PsiMethod)myHelper.getToSearchFor();
+
+ final boolean methodsToProcessAreDifferent = myMethod != toSearchFor;
+ if (myHelper.generateDelegate()) {
+ generateDelegate(myMethod, data.getParameterInitializer(), myProject);
+ if (methodsToProcessAreDifferent) {
+ final GrMethod method = generateDelegate(toSearchFor, data.getParameterInitializer(), myProject);
+ final PsiClass containingClass = method.getContainingClass();
+ if (containingClass != null && containingClass.isInterface()) {
+ final GrOpenBlock block = method.getBlock();
+ if (block != null) {
+ block.delete();
+ }
+ }
+ }
+ }
+
+ // Changing signature of initial method
+ // (signature of myMethodToReplaceIn will be either changed now or have already been changed)
+ final FieldConflictsResolver fieldConflictsResolver = new FieldConflictsResolver(myHelper.getName(), myMethod.getBlock());
+ changeMethodSignatureAndResolveFieldConflicts(new UsageInfo(myMethod), usages, data);
+ if (methodsToProcessAreDifferent) {
+ changeMethodSignatureAndResolveFieldConflicts(new UsageInfo(toSearchFor), usages, data);
+ }
+
+ // Replacing expression occurrences
+ for (UsageInfo usage : usages) {
+ if (usage instanceof ChangedMethodCallInfo) {
+ PsiElement element = usage.getElement();
+
+ processChangedMethodCall(element, myHelper, myProject);
+ }
+ }
+
+ final GrStatement newStatement = ExtractUtil.replaceStatement(myMethod.getBlock(), myHelper);
+ if (myEditor != null) {
+ PsiDocumentManager.getInstance(myProject).commitDocument(myEditor.getDocument());
+ myEditor.getCaretModel().moveToOffset(ExtractUtil.getCaretOffset(newStatement));
+ }
+
+ fieldConflictsResolver.fix();
+ }
+
+ private class IntroduceParameterDataAdapter implements IntroduceParameterData {
+
+ private final GrClosableBlock myClosure;
+ private final GrExpressionWrapper myWrapper;
+ private final PsiType myType;
+
+ private IntroduceParameterDataAdapter() {
+ myClosure = generateClosure();
+ myWrapper = new GrExpressionWrapper(myClosure);
+ myType = JavaPsiFacade.getElementFactory(myProject).createTypeFromText(GroovyCommonClassNames.GROOVY_LANG_CLOSURE, myMethod);
+ }
+
+ @NotNull
+ @Override
+ public Project getProject() {
+ return myProject;
+ }
+
+ @Override
+ public PsiMethod getMethodToReplaceIn() {
+ return myMethod;
+ }
+
+ @NotNull
+ @Override
+ public PsiMethod getMethodToSearchFor() {
+ return (PsiMethod)myHelper.getToSearchFor();
+ }
+
+ @Override
+ public ExpressionWrapper getParameterInitializer() {
+ return myWrapper;
+ }
+
+ @NotNull
+ @Override
+ public String getParameterName() {
+ return myHelper.getName();
+ }
+
+ @Override
+ public int getReplaceFieldsWithGetters() {
+ return IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_NONE; //todo add option to dialog
+ }
+
+ @Override
+ public boolean isDeclareFinal() {
+ return myHelper.declareFinal();
+ }
+
+ @Override
+ public boolean isGenerateDelegate() {
+ return false; //todo
+ }
+
+ @NotNull
+ @Override
+ public PsiType getForcedType() {
+ return myType;
+ }
+
+ @NotNull
+ @Override
+ public TIntArrayList getParametersToRemove() {
+ return myHelper.parametersToRemove();
+ }
+
+ }
+}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/closure/ExtractClosureHandler.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/closure/ExtractClosureHandler.java
new file mode 100644
index 000000000000..f0931a3c9b01
--- /dev/null
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/closure/ExtractClosureHandler.java
@@ -0,0 +1,173 @@
+/*
+ * 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.blocks.GrClosableBlock;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrMemberOwner;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
+import org.jetbrains.plugins.groovy.lang.psi.api.util.GrStatementOwner;
+import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringBundle;
+import org.jetbrains.plugins.groovy.refactoring.HelpID;
+import org.jetbrains.plugins.groovy.refactoring.extract.ExtractException;
+import org.jetbrains.plugins.groovy.refactoring.extract.ExtractHandlerBase;
+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 extends ExtractHandlerBase 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 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 callback = new Pass() {
+ public void pass(final GrExpression selectedValue) {
+ invoke(project, editor, file, selectedValue.getTextRange().getStartOffset(), selectedValue.getTextRange().getEndOffset());
+ }
+ };
+ final Function renderer = new Function() {
+ @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 {
+ invokeOnEditor(project, editor, file, start, end);
+ }
+ catch (ExtractException 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 callback) {
+ final List scopes = new ArrayList();
+ while (true) {
+ final GrParametersOwner parent = PsiTreeUtil.getParentOfType(place, GrMethod.class, GrClosableBlock.class);
+ if (parent == null) break;
+ scopes.add(parent);
+ place = parent;
+ }
+
+ if (scopes.size() == 0) {
+ throw new ExtractException(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);
+ }
+ }
+
+
+ @Override
+ public void performRefactoring(@NotNull final InitialInfo info,
+ @NotNull GrMemberOwner owner,
+ GrStatementOwner declarationOwner,
+ final Editor editor,
+ PsiElement startElement) {
+ findScope(startElement, editor, new PairFunction() {
+ @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;
+ }
+}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/closure/ExtractClosureHelper.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/closure/ExtractClosureHelper.java
new file mode 100644
index 000000000000..188b10ca1388
--- /dev/null
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/closure/ExtractClosureHelper.java
@@ -0,0 +1,111 @@
+/*
+ * 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.psi.JavaPsiFacade;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiType;
+import gnu.trove.TIntArrayList;
+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;
+
+/**
+ * @author Max Medvedev
+ */
+public class ExtractClosureHelper extends ExtractInfoHelperBase implements ExtractInfoHelper, GrIntroduceParameterSettings {
+
+ private final GrParametersOwner myOwner;
+ private final PsiElement myToSearchFor;
+
+ private String myName;
+ private boolean myFinal;
+ private TIntArrayList toRemove;
+ private boolean myGenerateDelegate;
+
+ public ExtractClosureHelper(InitialInfo info, GrParametersOwner owner, PsiElement toSearchFor, String name, boolean declareFinal) {
+ super(info);
+ myOwner = owner;
+ myToSearchFor = toSearchFor;
+ myName = name;
+ myFinal = declareFinal;
+ }
+
+ public GrParametersOwner getOwner() {
+ return myOwner;
+ }
+
+ public PsiElement getToSearchFor() {
+ return myToSearchFor;
+ }
+
+ public String getName() {
+ return myName;
+ }
+
+ public boolean declareFinal() {
+ 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;
+ }
+
+ @Override
+ public int replaceFieldsWithGetters() {
+ return 0;//todo
+ }
+
+ @Override
+ public boolean removeLocalVariable() {
+ return false;
+ }
+
+ @Override
+ public boolean replaceAllOccurrences() {
+ return false;
+ }
+
+ @Override
+ public PsiType getSelectedType() {
+ return JavaPsiFacade.getElementFactory(getProject()).createTypeFromText(GroovyCommonClassNames.GROOVY_LANG_CLOSURE, myOwner);
+ }
+
+ public boolean generateDelegate() {
+ return myGenerateDelegate;
+ }
+
+ public void setGenerateDelegate(boolean generateDelegate) {
+ myGenerateDelegate = generateDelegate;
+ }
+}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/closure/ExtractClosureProcessorBase.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/closure/ExtractClosureProcessorBase.java
new file mode 100644
index 000000000000..f65e361c69bf
--- /dev/null
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/closure/ExtractClosureProcessorBase.java
@@ -0,0 +1,75 @@
+/*
+ * 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.psi.PsiElement;
+import com.intellij.refactoring.BaseRefactoringProcessor;
+import com.intellij.refactoring.ui.UsageViewDescriptorAdapter;
+import com.intellij.usageView.UsageInfo;
+import com.intellij.usageView.UsageViewDescriptor;
+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;
+
+/**
+ * @author Max Medvedev
+ */
+public abstract class ExtractClosureProcessorBase extends BaseRefactoringProcessor {
+ protected final ExtractClosureHelper myHelper;
+
+ public ExtractClosureProcessorBase(@NotNull ExtractClosureHelper helper) {
+ super(helper.getProject());
+ myHelper = helper;
+ }
+
+ @NotNull
+ @Override
+ protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) {
+ return new UsageViewDescriptorAdapter() {
+ @NotNull
+ @Override
+ public PsiElement[] getElements() {
+ return new PsiElement[]{myHelper.getToSearchFor()};
+ }
+
+ @Override
+ public String getProcessedElementsHeader() {
+ return ExtractClosureHandler.EXTRACT_CLOSURE;
+ }
+ };
+ }
+
+ @Override
+ protected String getCommandName() {
+ return ExtractClosureHandler.EXTRACT_CLOSURE;
+ }
+
+ protected GrClosableBlock generateClosure() {
+ StringBuilder buffer = new StringBuilder();
+
+ buffer.append('{');
+ for (String p : ExtractUtil.getParameterString(myHelper, true)) {
+ buffer.append(p);
+ }
+ buffer.append("->\n");
+
+ ExtractUtil.generateBody(myHelper, false, buffer);
+ buffer.append('}');
+
+ return GroovyPsiElementFactory.getInstance(myHelper.getProject()).createClosureFromText(buffer.toString(), myHelper.getOwner());
+ }
+}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/closure/OtherLanguageUsageInfo.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/closure/OtherLanguageUsageInfo.java
new file mode 100644
index 000000000000..97bd9e7c5d39
--- /dev/null
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/closure/OtherLanguageUsageInfo.java
@@ -0,0 +1,29 @@
+/*
+ * 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.psi.PsiReference;
+import com.intellij.usageView.UsageInfo;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * @author Max Medvedev
+ */
+public class OtherLanguageUsageInfo extends UsageInfo {
+ public OtherLanguageUsageInfo(@NotNull PsiReference reference) {
+ super(reference);
+ }
+}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/method/ExtractMethodInfoHelper.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/method/ExtractMethodInfoHelper.java
index ed87a8dd84a5..f961980a6e28 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/method/ExtractMethodInfoHelper.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/method/ExtractMethodInfoHelper.java
@@ -16,9 +16,14 @@
package org.jetbrains.plugins.groovy.refactoring.extract.method;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiModifier;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrMemberOwner;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
import org.jetbrains.plugins.groovy.refactoring.extract.ExtractInfoHelperBase;
-import org.jetbrains.plugins.groovy.refactoring.extract.ExtractUtil;
import org.jetbrains.plugins.groovy.refactoring.extract.InitialInfo;
/**
@@ -30,14 +35,16 @@ public class ExtractMethodInfoHelper extends ExtractInfoHelperBase {
private boolean mySpecifyType = true;
private String myVisibility;
private String myName;
+ private final GrMemberOwner myOwner;
- public ExtractMethodInfoHelper(InitialInfo initialInfo, String name) {
+ public ExtractMethodInfoHelper(InitialInfo initialInfo, String name, GrMemberOwner owner) {
super(initialInfo);
+ myOwner = owner;
myVisibility = PsiModifier.PRIVATE;
myName = name;
- myIsStatic = ExtractUtil.canBeStatic(initialInfo.getStatements()[0]);
+ myIsStatic = canBeStatic(initialInfo.getStatements()[0]);
}
public boolean isStatic() {
@@ -67,4 +74,20 @@ public class ExtractMethodInfoHelper extends ExtractInfoHelperBase {
public void setName(String name) {
myName = name;
}
+
+ @NotNull
+ public GrMemberOwner getOwner() {
+ return myOwner;
+ }
+
+ private static boolean canBeStatic(GrStatement statement) {
+ PsiElement parent = statement.getParent();
+ while (parent != null && !(parent instanceof PsiFile)) {
+ if (parent instanceof GrMethod) {
+ return ((GrMethod) parent).hasModifierProperty(PsiModifier.STATIC);
+ }
+ parent = parent.getParent();
+ }
+ return false;
+ }
}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/method/GroovyExtractMethodDialog.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/method/GroovyExtractMethodDialog.java
index d6f2b0425d9c..8d888a0a7f0f 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/method/GroovyExtractMethodDialog.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/method/GroovyExtractMethodDialog.java
@@ -22,19 +22,30 @@ import com.intellij.openapi.help.HelpManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Splitter;
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiModifier;
+import com.intellij.psi.PsiSubstitutor;
import com.intellij.refactoring.HelpID;
import com.intellij.refactoring.ui.ComboBoxVisibilityPanel;
+import com.intellij.refactoring.ui.ConflictsDialog;
import com.intellij.refactoring.ui.MethodSignatureComponent;
+import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.intellij.ui.EditorTextField;
import com.intellij.ui.IdeBorderFactory;
+import com.intellij.util.ArrayUtil;
+import gnu.trove.TObjectHashingStrategy;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.GroovyFileType;
+import org.jetbrains.plugins.groovy.intentions.utils.DuplicatesUtil;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrMemberOwner;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
+import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass;
import org.jetbrains.plugins.groovy.refactoring.GroovyNamesUtil;
import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringBundle;
+import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringUtil;
import org.jetbrains.plugins.groovy.refactoring.extract.ExtractUtil;
import org.jetbrains.plugins.groovy.refactoring.extract.InitialInfo;
import org.jetbrains.plugins.groovy.refactoring.extract.ParameterTablePanel;
@@ -51,7 +62,10 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
+import java.util.ArrayList;
import java.util.EventListener;
+import java.util.List;
+import java.util.Map;
/**
* @author ilyas
@@ -71,10 +85,10 @@ public class GroovyExtractMethodDialog extends DialogWrapper {
private ParameterTablePanel myParameterTablePanel;
private final Project myProject;
- public GroovyExtractMethodDialog(InitialInfo info) {
+ public GroovyExtractMethodDialog(InitialInfo info, GrMemberOwner owner) {
super(info.getProject(), true);
myProject = info.getProject();
- myHelper = new ExtractMethodInfoHelper(info, "");
+ myHelper = new ExtractMethodInfoHelper(info, "", owner);
setUpNameField();
myParameterTablePanel.init(myHelper);
@@ -98,8 +112,8 @@ public class GroovyExtractMethodDialog extends DialogWrapper {
protected void doOKAction() {
String name = getEnteredName();
if (name == null) return;
- GrMethod method = ExtractUtil.createMethodByHelper(name, myHelper);
- if (method != null && !ExtractUtil.validateMethod(method, myHelper)) {
+ GrMethod method = ExtractUtil.createMethod(myHelper);
+ if (method != null && !validateMethod(method, myHelper)) {
return;
}
if (myCbSpecifyType.isEnabled()) {
@@ -232,6 +246,44 @@ public class GroovyExtractMethodDialog extends DialogWrapper {
};
}
+ private static boolean validateMethod(GrMethod method, ExtractMethodInfoHelper helper) {
+ ArrayList conflicts = new ArrayList();
+ GrMemberOwner owner = helper.getOwner();
+ PsiMethod[] methods = ArrayUtil.mergeArrays(owner.getAllMethods(), new PsiMethod[]{method}, PsiMethod.ARRAY_FACTORY);
+ final Map> map = DuplicatesUtil.factorDuplicates(methods, new TObjectHashingStrategy() {
+ public int computeHashCode(PsiMethod method) {
+ return method.getSignature(PsiSubstitutor.EMPTY).hashCode();
+ }
+
+ public boolean equals(PsiMethod method1, PsiMethod method2) {
+ return method1.getSignature(PsiSubstitutor.EMPTY).equals(method2.getSignature(PsiSubstitutor.EMPTY));
+ }
+ });
+
+ List list = map.get(method);
+ if (list == null) return true;
+ for (PsiMethod psiMethod : list) {
+ if (psiMethod != method) {
+ PsiClass containingClass = psiMethod.getContainingClass();
+ if (containingClass == null) return true;
+ String message = containingClass instanceof GroovyScriptClass ?
+ GroovyRefactoringBundle.message("method.is.already.defined.in.script", GroovyRefactoringUtil.getMethodSignature(method),
+ CommonRefactoringUtil.htmlEmphasize(containingClass.getQualifiedName())) :
+ GroovyRefactoringBundle.message("method.is.already.defined.in.class", GroovyRefactoringUtil.getMethodSignature(method),
+ CommonRefactoringUtil.htmlEmphasize(containingClass.getQualifiedName()));
+ conflicts.add(message);
+ }
+ }
+
+ return conflicts.size() <= 0 || reportConflicts(conflicts, helper.getProject());
+ }
+
+ private static boolean reportConflicts(final ArrayList conflicts, final Project project) {
+ ConflictsDialog conflictsDialog = new ConflictsDialog(project, conflicts);
+ conflictsDialog.show();
+ return conflictsDialog.isOK();
+ }
+
class DataChangedListener implements EventListener {
void dataChanged() {
update();
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/method/GroovyExtractMethodHandler.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/method/GroovyExtractMethodHandler.java
index ec50b31297f3..4522d2df7666 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/method/GroovyExtractMethodHandler.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/method/GroovyExtractMethodHandler.java
@@ -17,9 +17,9 @@
package org.jetbrains.plugins.groovy.refactoring.extract.method;
import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.application.AccessToken;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
-import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.ScrollType;
import com.intellij.openapi.editor.SelectionModel;
@@ -29,27 +29,29 @@ import com.intellij.psi.tree.IElementType;
import com.intellij.refactoring.RefactoringActionHandler;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.GrReferenceAdjuster;
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
import org.jetbrains.plugins.groovy.lang.lexer.TokenSets;
+import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
+import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement;
+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.expressions.GrReferenceExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrMemberOwner;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
import org.jetbrains.plugins.groovy.lang.psi.api.util.GrStatementOwner;
-import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil;
import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringBundle;
-import org.jetbrains.plugins.groovy.refactoring.extract.ExtractException;
-import org.jetbrains.plugins.groovy.refactoring.extract.ExtractHandlerBase;
-import org.jetbrains.plugins.groovy.refactoring.extract.ExtractUtil;
-import org.jetbrains.plugins.groovy.refactoring.extract.InitialInfo;
+import org.jetbrains.plugins.groovy.refactoring.extract.*;
+
+import java.util.ArrayList;
/**
* @author ilyas
*/
-public class GroovyExtractMethodHandler extends ExtractHandlerBase implements RefactoringActionHandler {
-
- private static final Logger LOG = Logger.getInstance(GroovyExtractMethodHandler.class);
+public class GroovyExtractMethodHandler extends ExtractHandlerBase implements RefactoringActionHandler {
protected static String REFACTORING_NAME = GroovyRefactoringBundle.message("extract.method.title");
private String myInvokeResult = "ok";
@@ -73,85 +75,60 @@ public class GroovyExtractMethodHandler extends ExtractHandlerBase 0;
- realStatement = null;
- for (GrStatement statement : newStatement) {
- realStatement = declarationOwner.addStatementBefore(statement, statements[0]);
- }
- assert realStatement != null;
- // remove old statements
- ExtractUtil.removeOldStatements(declarationOwner, helper);
- PsiImplUtil.removeNewLineAfter(realStatement);
- }
- else {
- // Expression call replace
- GrExpression methodCall = ExtractUtil.createMethodCallByHelper(methodName, helper);
- GrExpression oldExpr = (GrExpression)helper.getStatements()[0];
- realStatement = oldExpr.replaceWithExpression(methodCall, true);
- }
- GrReferenceAdjuster.shortenReferences(realStatement);
-
- PsiElement prev = newMethod.getPrevSibling();
- IElementType elementType = prev.getNode().getElementType();
- if (!TokenSets.WHITE_SPACES_SET.contains(elementType) || !prev.getText().contains("\n")) {
- newMethod.getParent().getNode().addLeaf(GroovyTokenTypes.mNLS, "\n", newMethod.getNode());
- }
+ createMethod(helper, owner, startElement);
+ GrStatement realStatement = ExtractUtil.replaceStatement(declarationOwner, helper);
// move to offset
if (editor != null) {
PsiDocumentManager.getInstance(helper.getProject()).commitDocument(editor.getDocument());
+ editor.getSelectionModel().removeSelection();
editor.getCaretModel().moveToOffset(ExtractUtil.getCaretOffset(realStatement));
}
}
- catch (IncorrectOperationException e) {
- LOG.error(e);
+ finally {
+ lock.finish();
}
}
- };
-
- Project project = helper.getProject();
- CommandProcessor.getInstance().executeCommand(project, new Runnable() {
- public void run() {
- ApplicationManager.getApplication().runWriteAction(runnable);
- editor.getSelectionModel().removeSelection();
- }
}, REFACTORING_NAME, null);
}
- @Override
- public ExtractMethodInfoHelper getSettings(@NotNull InitialInfo initialInfo) {
+ private static void createMethod(ExtractMethodInfoHelper helper, GrMemberOwner owner, PsiElement startElement) {
+ final GrMethod method = ExtractUtil.createMethod(helper);
+ PsiElement anchor = calculateAnchorToInsertBefore(owner, startElement);
+ GrMethod newMethod = owner.addMemberDeclaration(method, anchor);
+ renameParameterOccurrences(newMethod, helper);
+ GrReferenceAdjuster.shortenReferences(newMethod);
+ PsiElement prev = newMethod.getPrevSibling();
+ IElementType elementType = prev.getNode().getElementType();
+ if (!TokenSets.WHITE_SPACES_SET.contains(elementType) || !prev.getText().contains("\n")) {
+ newMethod.getParent().getNode().addLeaf(GroovyTokenTypes.mNLS, "\n", newMethod.getNode());
+ }
+ }
+
+ @Nullable
+ private static ExtractMethodInfoHelper getSettings(@NotNull InitialInfo initialInfo, GrMemberOwner owner) {
if (ApplicationManager.getApplication().isUnitTestMode()) {
- final ExtractMethodInfoHelper helper = new ExtractMethodInfoHelper(initialInfo, "testMethod");
+ final ExtractMethodInfoHelper helper = new ExtractMethodInfoHelper(initialInfo, "testMethod", owner);
final PsiType type = helper.getOutputType();
- if (type.equalsToText(CommonClassNames.JAVA_LANG_OBJECT) || type.equalsToText("void")) {
+ if (type.equalsToText(CommonClassNames.JAVA_LANG_OBJECT) || PsiType.VOID.equals(type)) {
helper.setSpecifyType(false);
}
return helper;
}
- GroovyExtractMethodDialog dialog = new GroovyExtractMethodDialog(initialInfo);
+ GroovyExtractMethodDialog dialog = new GroovyExtractMethodDialog(initialInfo, owner);
dialog.show();
if (!dialog.isOK()) return null;
@@ -166,4 +143,58 @@ public class GroovyExtractMethodHandler extends ExtractHandlerBase result = new ArrayList();
+ if (!oldName.equals(newName)) {
+ for (final GrStatement statement : statements) {
+ statement.accept(new PsiRecursiveElementVisitor() {
+ public void visitElement(final PsiElement element) {
+ super.visitElement(element);
+ if (element instanceof GrReferenceExpression) {
+ GrReferenceExpression expr = (GrReferenceExpression) element;
+ if (!expr.isQualified() && oldName.equals(expr.getName())) {
+ result.add(expr);
+ }
+ }
+ }
+ });
+ for (GrExpression expr : result) {
+ expr.replaceWithExpression(factory.createExpressionFromText(newName), false);
+ }
+ }
+ }
+ }
+ }
}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/GrIntroduceContext.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/GrIntroduceContext.java
index 184289237cb9..28b2a08cf93d 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/GrIntroduceContext.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/GrIntroduceContext.java
@@ -1,9 +1,12 @@
/*
- * Copyright 2000-2010 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.
* 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.
@@ -34,7 +37,7 @@ public class GrIntroduceContext {
public GrIntroduceContext(Project project,
Editor editor,
- GrExpression expression,
+ @Nullable GrExpression expression,
PsiElement[] occurrences,
PsiElement scope,
@Nullable GrVariable var) {
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/AnySupers.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/AnySupers.java
index 46606a7df3e1..b9cdb2e1e309 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/AnySupers.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/AnySupers.java
@@ -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.
@@ -21,7 +21,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrSuperR
/**
* @author Medvedev Max
*/
-class AnySupers extends GroovyRecursiveElementVisitor {
+public class AnySupers extends GroovyRecursiveElementVisitor {
boolean myContainsSupers = false;
@Override
@@ -30,7 +30,7 @@ class AnySupers extends GroovyRecursiveElementVisitor {
myContainsSupers = true;
}
- boolean isResult() {
+ public boolean isResult() {
return myContainsSupers;
}
}
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/GrIntroduceParameterProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/GrIntroduceParameterProcessor.java
index 52b0743f2b85..2f1314121c48 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/GrIntroduceParameterProcessor.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/GrIntroduceParameterProcessor.java
@@ -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.
@@ -29,8 +29,6 @@ import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.introduceParameter.*;
import com.intellij.refactoring.ui.UsageViewDescriptorAdapter;
import com.intellij.refactoring.util.CommonRefactoringUtil;
-import com.intellij.refactoring.util.ConflictsUtil;
-import com.intellij.refactoring.util.RefactoringUIUtil;
import com.intellij.refactoring.util.usageInfo.DefaultConstructorImplicitUsageInfo;
import com.intellij.refactoring.util.usageInfo.NoConstructorClassUsageInfo;
import com.intellij.usageView.UsageInfo;
@@ -38,23 +36,14 @@ import com.intellij.usageView.UsageViewDescriptor;
import com.intellij.usageView.UsageViewUtil;
import com.intellij.util.containers.MultiMap;
import gnu.trove.TIntArrayList;
-import gnu.trove.TIntProcedure;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
-import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
-import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList;
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.expressions.path.GrMethodCallExpression;
-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.api.types.GrClosureSignature;
-import org.jetbrains.plugins.groovy.lang.psi.impl.types.GrClosureSignatureUtil;
-import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.List;
/**
* @author Maxim.Medvedev
@@ -99,7 +88,10 @@ public class GrIntroduceParameterProcessor extends BaseRefactoringProcessor impl
MultiMap conflicts = new MultiMap();
if (!mySettings.generateDelegate()) {
- detectAccessibilityConflicts(usagesIn, conflicts);
+ GroovyIntroduceParameterUtil.detectAccessibilityConflicts(myContext.expression, usagesIn, conflicts,
+ mySettings.replaceFieldsWithGetters() != IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_NONE,
+ myProject
+ );
}
final GrMethod toReplaceIn = (GrMethod)myContext.toReplaceIn;
@@ -127,41 +119,6 @@ public class GrIntroduceParameterProcessor extends BaseRefactoringProcessor impl
return showConflicts(conflicts, usagesIn);
}
- private void detectAccessibilityConflicts(final UsageInfo[] usageArray, MultiMap conflicts) {
- if (myContext.expression == null) return;
-
- final ReferencedElementsCollector collector = new ReferencedElementsCollector();
- myContext.expression.accept(collector);
- final List result = collector.getResult();
- if (result.isEmpty()) return;
-
- for (final UsageInfo usageInfo : usageArray) {
- if (!(usageInfo instanceof ExternalUsageInfo) || !IntroduceParameterUtil.isMethodUsage(usageInfo)) continue;
-
- final PsiElement place = usageInfo.getElement();
- for (PsiElement element : result) {
- if (element instanceof PsiField &&
- mySettings.replaceFieldsWithGetters() != IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_NONE) {
- //check getter access instead
- final PsiClass psiClass = ((PsiField)element).getContainingClass();
- LOG.assertTrue(psiClass != null);
- final PsiMethod method = GroovyPropertyUtils.findGetterForField((PsiField)element);
- if (method != null) {
- element = method;
- }
- }
- if (element instanceof PsiMember &&
- !JavaPsiFacade.getInstance(myProject).getResolveHelper().isAccessible((PsiMember)element, place, null)) {
- String message = RefactoringBundle.message(
- "0.is.not.accessible.from.1.value.for.introduced.parameter.in.that.method.call.will.be.incorrect",
- RefactoringUIUtil.getDescription(element, true),
- RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(place), true));
- conflicts.putValue(element, message);
- }
- }
- }
- }
-
@NotNull
@Override
protected UsageInfo[] findUsages() {
@@ -220,7 +177,7 @@ public class GrIntroduceParameterProcessor extends BaseRefactoringProcessor impl
PsiType initializerType = mySettings.getSelectedType();
- // Changing external occurences (the tricky part)
+ // Changing external occurrences (the tricky part)
IntroduceParameterUtil.processUsages(usages, this);
@@ -229,9 +186,9 @@ public class GrIntroduceParameterProcessor extends BaseRefactoringProcessor impl
final boolean methodsToProcessAreDifferent = toReplaceIn != toSearchFor;
if (mySettings.generateDelegate()) {
- generateDelegate(toReplaceIn);
+ GroovyIntroduceParameterUtil.generateDelegate(toReplaceIn, myParameterInitializer, myProject);
if (methodsToProcessAreDifferent) {
- final GrMethod method = generateDelegate(toSearchFor);
+ final GrMethod method = GroovyIntroduceParameterUtil.generateDelegate(toSearchFor, myParameterInitializer, myProject);
final PsiClass containingClass = method.getContainingClass();
if (containingClass != null && containingClass.isInterface()) {
final GrOpenBlock block = method.getBlock();
@@ -255,12 +212,12 @@ public class GrIntroduceParameterProcessor extends BaseRefactoringProcessor impl
if (myContext.var != null) myContext.var.delete();
- // Replacing expression occurences
+ // Replacing expression occurrences
for (UsageInfo usage : usages) {
if (usage instanceof ChangedMethodCallInfo) {
PsiElement element = usage.getElement();
- processChangedMethodCall(element);
+ GroovyIntroduceParameterUtil.processChangedMethodCall(element, mySettings, myProject);
}
else if (usage instanceof InternalUsageInfo) {
PsiElement element = usage.getElement();
@@ -281,86 +238,6 @@ public class GrIntroduceParameterProcessor extends BaseRefactoringProcessor impl
fieldConflictsResolver.fix();
}
- private GrMethod generateDelegate(PsiMethod prototype) {
- final GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(myProject);
-
- GrMethod result;
- if (prototype instanceof GrMethod) {
- result = (GrMethod)prototype.copy();
- }
- else {
- StringBuilder builder = new StringBuilder();
- builder.append(prototype.getModifierList().getText()).append(' ');
-
- if (prototype.getReturnTypeElement() != null ) {
- builder.append(prototype.getReturnTypeElement().getText());
- }
- builder.append(' ').append(prototype.getName());
- builder.append(prototype.getParameterList().getText());
- builder.append("{}");
- result = factory.createMethodFromText(builder.toString());
- }
-
- StringBuilder call = new StringBuilder();
- call.append("def foo(){\n").append(prototype.getName()).append('(');
- final GrParameter[] parameters = result.getParameters();
- for (GrParameter parameter : parameters) {
- call.append(parameter.getName()).append(", ");
- }
- call.append(myParameterInitializer.getText());
- call.append(");\n}");
- final GrOpenBlock block = factory.createMethodFromText(call.toString()).getBlock();
-
- result.getBlock().replace(block);
- final PsiElement parent = prototype.getParent();
- return (GrMethod)parent.addBefore(result, prototype);
- }
-
- private void processChangedMethodCall(PsiElement element) {
- if (element.getParent() instanceof GrMethodCallExpression) {
- GrMethodCallExpression methodCall = (GrMethodCallExpression)element.getParent();
-
- GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(myProject);
- GrExpression expression = factory.createExpressionFromText(mySettings.getName(), null);
- final GrArgumentList argList = methodCall.getArgumentList();
- final PsiElement[] exprs = argList.getAllArguments();
-
- if (exprs.length > 0) {
- argList.addAfter(expression, exprs[exprs.length - 1]);
- }
- else {
- argList.add(expression);
- }
-
- removeParametersFromCall(methodCall, argList);
-
- }
- else {
- LOG.error(element.getParent());
- }
-
- }
-
- private void removeParametersFromCall(GrMethodCallExpression methodCall, GrArgumentList argList) {
- final GroovyResolveResult resolveResult = methodCall.advancedResolve();
- final PsiElement resolved = resolveResult.getElement();
- LOG.assertTrue(resolved instanceof PsiMethod);
- final GrClosureSignature signature = GrClosureSignatureUtil.createSignature((PsiMethod)resolved, resolveResult.getSubstitutor());
- final GrClosureSignatureUtil.ArgInfo[] argInfos =
- GrClosureSignatureUtil.mapParametersToArguments(signature, argList, methodCall, methodCall.getClosureArguments());
- LOG.assertTrue(argInfos != null);
- mySettings.parametersToRemove().forEach(new TIntProcedure() {
- @Override
- public boolean execute(int value) {
- final List args = argInfos[value].args;
- for (PsiElement arg : args) {
- arg.delete();
- }
- return true;
- }
- });
- }
-
@Override
protected String getCommandName() {
return RefactoringBundle.message("introduce.parameter.command", UsageViewUtil.getDescriptiveName(myContext.toReplaceIn));
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/GroovyIntroduceParameterUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/GroovyIntroduceParameterUtil.java
index 243aca27d665..8cd35f39f01b 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/GroovyIntroduceParameterUtil.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/GroovyIntroduceParameterUtil.java
@@ -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.
@@ -16,26 +16,44 @@
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.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;
+import com.intellij.refactoring.introduceParameter.IntroduceParameterUtil;
+import com.intellij.refactoring.util.ConflictsUtil;
+import com.intellij.refactoring.util.RefactoringUIUtil;
+import com.intellij.usageView.UsageInfo;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.Processor;
import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.containers.MultiMap;
import gnu.trove.TIntArrayList;
import gnu.trove.TIntProcedure;
import gnu.trove.TObjectIntHashMap;
import org.jetbrains.annotations.Nullable;
+import org.jetbrains.plugins.groovy.lang.GrReferenceAdjuster;
+import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
+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.arguments.GrArgumentList;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrOpenBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCall;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrThisReferenceExpression;
+import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression;
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.api.types.GrClosureSignature;
import org.jetbrains.plugins.groovy.lang.psi.impl.types.GrClosureSignatureUtil;
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils;
@@ -156,6 +174,143 @@ public class GroovyIntroduceParameterUtil {
});
}
+ public static void detectAccessibilityConflicts(@Nullable GroovyPsiElement elementToProcess,
+ final UsageInfo[] usages,
+ MultiMap conflicts,
+ boolean replaceFieldsWithGetters,
+ Project project) {
+ if (elementToProcess == null) return;
+
+ final ReferencedElementsCollector collector = new ReferencedElementsCollector();
+ elementToProcess.accept(collector);
+ final List result = collector.getResult();
+ if (result.isEmpty()) return;
+
+ for (final UsageInfo usageInfo : usages) {
+ if (!(usageInfo instanceof ExternalUsageInfo) || !IntroduceParameterUtil.isMethodUsage(usageInfo)) continue;
+
+ final PsiElement place = usageInfo.getElement();
+ for (PsiElement element : result) {
+ if (element instanceof PsiField && replaceFieldsWithGetters) {
+ //check getter access instead
+ final PsiClass psiClass = ((PsiField)element).getContainingClass();
+ LOG.assertTrue(psiClass != null);
+ final PsiMethod method = GroovyPropertyUtils.findGetterForField((PsiField)element);
+ if (method != null) {
+ element = method;
+ }
+ }
+ if (element instanceof PsiMember &&
+ !JavaPsiFacade.getInstance(project).getResolveHelper().isAccessible((PsiMember)element, place, null)) {
+ String message = RefactoringBundle.message(
+ "0.is.not.accessible.from.1.value.for.introduced.parameter.in.that.method.call.will.be.incorrect",
+ RefactoringUIUtil.getDescription(element, true),
+ RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(place), true));
+ conflicts.putValue(element, message);
+ }
+ }
+ }
+ }
+
+ public static void processChangedMethodCall(PsiElement element, GrIntroduceParameterSettings settings, Project project) {
+ if (!(element.getParent() instanceof GrMethodCallExpression)) {
+ LOG.error(element.getParent());
+ return;
+ }
+
+ GrMethodCallExpression methodCall = (GrMethodCallExpression)element.getParent();
+
+ GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(project);
+ final String name = settings.getName();
+ LOG.assertTrue(name != null);
+ GrExpression expression = factory.createExpressionFromText(name, null);
+ final GrArgumentList argList = methodCall.getArgumentList();
+ final PsiElement[] exprs = argList.getAllArguments();
+
+ if (exprs.length > 0) {
+ argList.addAfter(expression, exprs[exprs.length - 1]);
+ }
+ else {
+ argList.add(expression);
+ }
+
+ removeParametersFromCall(methodCall, argList, settings);
+ }
+
+ private static void removeParametersFromCall(GrMethodCallExpression methodCall,
+ GrArgumentList argList,
+ GrIntroduceParameterSettings settings) {
+ final GroovyResolveResult resolveResult = methodCall.advancedResolve();
+ final PsiElement resolved = resolveResult.getElement();
+ LOG.assertTrue(resolved instanceof PsiMethod);
+ final GrClosureSignature signature = GrClosureSignatureUtil.createSignature((PsiMethod)resolved, resolveResult.getSubstitutor());
+ final GrClosureSignatureUtil.ArgInfo[] argInfos =
+ GrClosureSignatureUtil.mapParametersToArguments(signature, argList, methodCall, methodCall.getClosureArguments());
+ LOG.assertTrue(argInfos != null);
+ settings.parametersToRemove().forEach(new TIntProcedure() {
+ @Override
+ public boolean execute(int value) {
+ final List args = argInfos[value].args;
+ for (PsiElement arg : args) {
+ arg.delete();
+ }
+ return true;
+ }
+ });
+ }
+
+ public static GrMethod generateDelegate(PsiMethod prototype, IntroduceParameterData.ExpressionWrapper initializer, Project project) {
+ final GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(project);
+
+ GrMethod result;
+ if (prototype instanceof GrMethod) {
+ result = (GrMethod)prototype.copy();
+ }
+ else {
+ StringBuilder builder = new StringBuilder();
+ builder.append(prototype.getModifierList().getText()).append(' ');
+
+ if (prototype.getReturnTypeElement() != null ) {
+ builder.append(prototype.getReturnTypeElement().getText());
+ }
+ builder.append(' ').append(prototype.getName());
+ builder.append(prototype.getParameterList().getText());
+ builder.append("{}");
+ result = factory.createMethodFromText(builder.toString());
+ }
+
+ StringBuilder call = new StringBuilder();
+ call.append("def foo(){\n");
+ final GrParameter[] parameters = result.getParameters();
+ call.append(prototype.getName());
+ if (initializer.getExpression() instanceof GrClosableBlock) {
+ if (parameters.length > 0) {
+ call.append('(');
+ for (GrParameter parameter : parameters) {
+ call.append(parameter.getName()).append(", ");
+ }
+ call.replace(call.length()-2, call.length(), ")");
+ }
+ call.append(initializer.getText());
+ }
+ else {
+ call.append('(');
+ for (GrParameter parameter : parameters) {
+ call.append(parameter.getName()).append(", ");
+ }
+ call.append(initializer.getText());
+ call.append(")");
+ }
+ call.append("\n}");
+ final GrOpenBlock block = factory.createMethodFromText(call.toString()).getBlock();
+
+ result.getBlock().replace(block);
+ final PsiElement parent = prototype.getParent();
+ final GrMethod method = (GrMethod)parent.addBefore(result, prototype);
+ GrReferenceAdjuster.shortenReferences(method);
+ return method;
+ }
+
private static class FieldSearcher extends GroovyRecursiveElementVisitor {
PsiClass myClass;
private final List result = new ArrayList();
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/java2groovy/OldReferencesResolver.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/java2groovy/OldReferencesResolver.java
index e0ab628ba4b5..13059b33361a 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/java2groovy/OldReferencesResolver.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/parameter/java2groovy/OldReferencesResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2000-2009 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.
@@ -52,8 +52,7 @@ import static com.intellij.codeInsight.ChangeContextUtil.*;
*/
public class OldReferencesResolver {
- private static final Logger LOG =
- Logger.getInstance("#org.jetbrains.plugins.groovy.refactoring.introduce.parameter.java2groovy.OldReferencesResolver");
+ private static final Logger LOG = Logger.getInstance(OldReferencesResolver.class);
private final GrCall myContext;
private final GrExpression myExpr;
diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extract/closure/ExtractClosureTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extract/closure/ExtractClosureTest.groovy
new file mode 100644
index 000000000000..07af99ebf109
--- /dev/null
+++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extract/closure/ExtractClosureTest.groovy
@@ -0,0 +1,156 @@
+/*
+ * 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.psi.PsiElement
+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.util.TestUtils
+
+/**
+ * @author Max Medvedev
+ */
+public class ExtractClosureTest extends LightGroovyTestCase {
+ @Override
+ protected String getBasePath() {
+ return "${TestUtils.testDataPath}groovy/refactoring/extractMethod/";
+ }
+
+
+ private void doTest(String before, String after) {
+ doTest(before, after, [], [])
+ }
+
+ private void doTest(String before, String after, List toRemove, List 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)
+ }
+ return settings
+ }
+ }
+
+ handler.invoke myFixture.project, myFixture.editor, myFixture.file, model.selectionStart, model.selectionEnd
+ myFixture.checkResult after
+ }
+
+
+ void testSimple() {
+ doTest('''
+def foo(String s) {
+ s+=2
+ print s
+}
+
+foo('a')
+''', '''
+def foo(String s, Closure closure) {
+ s+=2
+ closure(s)
+}
+
+foo('a') {String s ->
+ print s
+}
+''')
+ }
+
+ void testRemoveUnused() {
+ doTest('''
+class X {
+ def foo(String s) {
+ print s
+ }
+}
+
+new X().foo('a')
+''', '''
+class X {
+ def foo(Closure closure) {
+ closure()
+ }
+}
+
+new X().foo {->
+ print 'a'
+}
+''', [0], [0])
+
+ }
+
+ void testRemoveUnusedAndGenerateLocal() {
+ doTest('''
+def foo(String s) {
+ s+=2
+ print s
+}
+
+foo('a')
+''', '''
+def foo(Closure closure) {
+ closure()
+}
+
+foo {->
+ String s = 'a'
+ s += 2
+ print s
+}
+''', [0], [0])
+
+ }
+
+ void testInsertQualifier() {
+ doTest('''
+class X {
+ def foo(String s) {
+ bar()
+ }
+ def bar(){}
+}
+
+new X().foo('a')
+''', '''
+class X {
+ def foo(Closure closure) {
+ closure()
+ }
+ def bar(){}
+}
+
+final X x = new X()
+x.foo {->
+ x.bar()
+}
+''', [0], [])
+
+ }
+}
diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extract/method/ExtractMethodTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extract/method/ExtractMethodTest.java
index ca9a658db497..8cf703b51cd8 100644
--- a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extract/method/ExtractMethodTest.java
+++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extract/method/ExtractMethodTest.java
@@ -106,5 +106,6 @@ public class ExtractMethodTest extends LightGroovyTestCase {
public void testAOOBE() {doTest();}
public void testWildCardReturnType() {doTest();}
+ public void testParamChangedInsideExtractedMethod() {doTest();}
}
\ No newline at end of file
diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/introduceParameter/GrIntroduceParameterTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/introduceParameter/GrIntroduceParameterTest.java
index 446bd52004d4..fc60dffd3b1a 100644
--- a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/introduceParameter/GrIntroduceParameterTest.java
+++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/introduceParameter/GrIntroduceParameterTest.java
@@ -333,4 +333,5 @@ public class GrIntroduceParameterTest extends LightCodeInsightFixtureTestCase {
public void testClosureArg() {doTest(IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_NONE, false, false);}
public void testClosureArgWithEmptyArgList() {doTest(IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_NONE, true, false);}
+ public void testScriptMethod() {doTest(IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_NONE, true, false);}
}
diff --git a/plugins/groovy/testdata/groovy/refactoring/extractMethod/inter1.test b/plugins/groovy/testdata/groovy/refactoring/extractMethod/inter1.test
index 7e98291048d8..3194f14f5856 100644
--- a/plugins/groovy/testdata/groovy/refactoring/extractMethod/inter1.test
+++ b/plugins/groovy/testdata/groovy/refactoring/extractMethod/inter1.test
@@ -15,7 +15,7 @@ def i = 6
i = testMethod()
private int testMethod() {
- int i
+ def i
while (true) {
println "preved"
i = 42
diff --git a/plugins/groovy/testdata/groovy/refactoring/extractMethod/meth_em3.test b/plugins/groovy/testdata/groovy/refactoring/extractMethod/meth_em3.test
index 76651aa31c70..2a75d8f62a7f 100644
--- a/plugins/groovy/testdata/groovy/refactoring/extractMethod/meth_em3.test
+++ b/plugins/groovy/testdata/groovy/refactoring/extractMethod/meth_em3.test
@@ -11,7 +11,7 @@ protected static def getGeneratedFileNames(String name, int boo) {
}
private static ArrayList testMethod() {
- ArrayList names
+ def names
names = new ArrayList()
return names
}
\ No newline at end of file
diff --git a/plugins/groovy/testdata/groovy/refactoring/extractMethod/paramChangedInsideExtractedMethod.test b/plugins/groovy/testdata/groovy/refactoring/extractMethod/paramChangedInsideExtractedMethod.test
new file mode 100644
index 000000000000..06aa4dc8c045
--- /dev/null
+++ b/plugins/groovy/testdata/groovy/refactoring/extractMethod/paramChangedInsideExtractedMethod.test
@@ -0,0 +1,14 @@
+def foo(String s){
+ s = 'a'
+ print s
+}
+-----
+def foo(String s){
+ testMethod()
+}
+
+private testMethod() {
+ String s
+ s = 'a'
+ print s
+}
diff --git a/plugins/groovy/testdata/refactoring/introduceParameterGroovy/delegate1/Delegate1MyClass_after.groovy b/plugins/groovy/testdata/refactoring/introduceParameterGroovy/delegate1/Delegate1MyClass_after.groovy
index 09825055dd40..30aa351c71f4 100644
--- a/plugins/groovy/testdata/refactoring/introduceParameterGroovy/delegate1/Delegate1MyClass_after.groovy
+++ b/plugins/groovy/testdata/refactoring/introduceParameterGroovy/delegate1/Delegate1MyClass_after.groovy
@@ -1,5 +1,20 @@
+/*
+ * 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.
+ */
def foo() {
- foo("foo");
+ foo("foo")
}
def foo(String anObject) {
diff --git a/plugins/groovy/testdata/refactoring/introduceParameterGroovy/delegate2/Delegate2MyClass_after.groovy b/plugins/groovy/testdata/refactoring/introduceParameterGroovy/delegate2/Delegate2MyClass_after.groovy
index 4b60354d4304..a610ba8aebe5 100644
--- a/plugins/groovy/testdata/refactoring/introduceParameterGroovy/delegate2/Delegate2MyClass_after.groovy
+++ b/plugins/groovy/testdata/refactoring/introduceParameterGroovy/delegate2/Delegate2MyClass_after.groovy
@@ -1,5 +1,20 @@
+/*
+ * 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.
+ */
def foo(def p) {
- foo(p, "foo");
+ foo(p, "foo")
}
def foo(def p, String anObject) {
diff --git a/plugins/groovy/testdata/refactoring/introduceParameterGroovy/delegaterInSuper/DelegaterInSuperMyClass_after.groovy b/plugins/groovy/testdata/refactoring/introduceParameterGroovy/delegaterInSuper/DelegaterInSuperMyClass_after.groovy
index aa6dbf5bd5d4..1f64cc5f64b1 100644
--- a/plugins/groovy/testdata/refactoring/introduceParameterGroovy/delegaterInSuper/DelegaterInSuperMyClass_after.groovy
+++ b/plugins/groovy/testdata/refactoring/introduceParameterGroovy/delegaterInSuper/DelegaterInSuperMyClass_after.groovy
@@ -1,6 +1,21 @@
+/*
+ * 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.
+ */
class Base {
def foo() {
- foo(123);
+ foo(123)
}
def foo(int anObject){}
@@ -8,7 +23,7 @@ class Base {
class Inh extends Base {
def foo() {
- foo(123);
+ foo(123)
}
def foo(int anObject) {print anObject}
diff --git a/plugins/groovy/testdata/refactoring/introduceParameterGroovy/scriptMethod/ScriptMethodMyClass.groovy b/plugins/groovy/testdata/refactoring/introduceParameterGroovy/scriptMethod/ScriptMethodMyClass.groovy
new file mode 100644
index 000000000000..55489d4c13ff
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/introduceParameterGroovy/scriptMethod/ScriptMethodMyClass.groovy
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+def foo(String s) {
+ print(s + 1)
+}
+
+foo('a')
\ No newline at end of file
diff --git a/plugins/groovy/testdata/refactoring/introduceParameterGroovy/scriptMethod/ScriptMethodMyClass_after.groovy b/plugins/groovy/testdata/refactoring/introduceParameterGroovy/scriptMethod/ScriptMethodMyClass_after.groovy
new file mode 100644
index 000000000000..4b33be5d7ffe
--- /dev/null
+++ b/plugins/groovy/testdata/refactoring/introduceParameterGroovy/scriptMethod/ScriptMethodMyClass_after.groovy
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+def foo(def anObject) {
+ print(anObject)
+}
+
+foo('a' + 1)
\ No newline at end of file