diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/GroovyIntentionsBundle.properties b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/GroovyIntentionsBundle.properties
index bb9ff1941211..340be06e9ffc 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/GroovyIntentionsBundle.properties
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/GroovyIntentionsBundle.properties
@@ -103,3 +103,5 @@ closure.is.accessed.outside.of.groovy=Field {0} is accessed outside of Gr
write.access.to.closure.variable=Write access to field {0}
field.is.used.in.argument.label=Field {0} is used in argument label
method.with.signature.already.exists=Method with signature {0} already exists
+field.already.exists=Field {0} already exists
+method.is.used.outside.of.groovy=Method is used outside of Groovy\
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/conversions/ConvertClosureToMethodIntention.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/conversions/ConvertClosureToMethodIntention.java
index 9853df9e106c..6c7103b31fa2 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/conversions/ConvertClosureToMethodIntention.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/conversions/ConvertClosureToMethodIntention.java
@@ -108,7 +108,9 @@ public class ConvertClosureToMethodIntention extends Intention {
}
}
final PsiClass containingClass = field.getContainingClass();
- final PsiType type = field.getTypeGroovy();
+ final GrExpression initializer = field.getInitializerGroovy();
+ LOG.assertTrue(initializer != null);
+ final PsiType type = initializer.getType();
LOG.assertTrue(type instanceof GrClosureType);
final GrClosureSignature signature = ((GrClosureType)type).getSignature();
final List signatures = GrClosureSignatureUtil.generateAllMethodSignaturesByClosureSignature(fieldName, signature);
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/conversions/ConvertMethodToClosureIntention.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/conversions/ConvertMethodToClosureIntention.java
index 7823410e28b3..6bf530129f07 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/conversions/ConvertMethodToClosureIntention.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/conversions/ConvertMethodToClosureIntention.java
@@ -16,19 +16,34 @@
package org.jetbrains.plugins.groovy.intentions.conversions;
+import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.DialogWrapper;
+import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiField;
+import com.intellij.psi.PsiReference;
+import com.intellij.psi.search.searches.MethodReferencesSearch;
+import com.intellij.refactoring.ui.ConflictsDialog;
import com.intellij.util.IncorrectOperationException;
+import com.intellij.util.containers.HashSet;
+import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.plugins.groovy.GroovyFileType;
+import org.jetbrains.plugins.groovy.intentions.GroovyIntentionsBundle;
import org.jetbrains.plugins.groovy.intentions.base.Intention;
import org.jetbrains.plugins.groovy.intentions.base.PsiElementPredicate;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifier;
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.expressions.GrReferenceExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinitionBody;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
+import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
+
+import java.util.Collection;
/**
@@ -43,21 +58,72 @@ public class ConvertMethodToClosureIntention extends Intention {
@Override
protected void processIntention(@NotNull PsiElement element, Project project, Editor editor) throws IncorrectOperationException {
- element = element.getParent();
- final GrMethod method = (GrMethod)element;
- StringBuilder builder = new StringBuilder(method.getTextLength());
- String modifiers = method.getModifierList().getText();
- if (modifiers.trim().length() == 0) {
- modifiers = GrModifier.DEF;
+ MultiMap conflicts = new MultiMap();
+ final GrMethod method = (GrMethod)element.getParent();
+
+ final PsiClass containingClass = method.getContainingClass();
+ final String methodName = method.getName();
+ final PsiField field = containingClass.findFieldByName(methodName, true);
+
+ if (field != null) {
+ conflicts.putValue(field, GroovyIntentionsBundle.message("field.already.exists", methodName));
}
- builder.append(modifiers).append(' ');
- builder.append(method.getName()).append("={");
- builder.append(method.getParameterList().getText()).append(" ->");
- final GrOpenBlock block = method.getBlock();
- builder.append(block.getText().substring(1));
- final GrVariableDeclaration variableDeclaration =
- GroovyPsiElementFactory.getInstance(element.getProject()).createFieldDeclarationFromText(builder.toString());
- method.replace(variableDeclaration);
+
+ final Collection references = MethodReferencesSearch.search(method).findAll();
+ final Collection usagesToConvert = new HashSet(references.size());
+ for (PsiReference ref : references) {
+ final PsiElement psiElement = ref.getElement();
+ if (!GroovyFileType.GROOVY_LANGUAGE.equals(psiElement.getLanguage())) {
+ conflicts.putValue(psiElement, GroovyIntentionsBundle.message("method.is.used.outside.of.groovy"));
+ } else if (!PsiUtil.isMethodUsage(psiElement)) {
+ if (psiElement instanceof GrReferenceExpression) {
+ if (((GrReferenceExpression)psiElement).hasMemberPointer()) {
+ usagesToConvert.add((GrReferenceExpression)psiElement);
+ }
+ }
+ }
+ }
+ if (conflicts.size()>0) {
+ ConflictsDialog conflictsDialog = new ConflictsDialog(project, conflicts, new Runnable() {
+ @Override
+ public void run() {
+ execute(method, usagesToConvert);
+ }
+ });
+ conflictsDialog.show();
+ if (conflictsDialog.getExitCode() != DialogWrapper.OK_EXIT_CODE) return;
+ }
+ execute(method, usagesToConvert);
+ }
+
+ private static void execute(final GrMethod method, final Collection usagesToConvert) {
+ ApplicationManager.getApplication().runWriteAction(new Runnable() {
+ public void run() {
+ GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(method.getProject());
+
+ StringBuilder builder = new StringBuilder(method.getTextLength());
+ String modifiers = method.getModifierList().getText();
+ if (modifiers.trim().length() == 0) {
+ modifiers = GrModifier.DEF;
+ }
+ builder.append(modifiers).append(' ');
+ builder.append(method.getName()).append("={");
+ builder.append(method.getParameterList().getText()).append(" ->");
+ final GrOpenBlock block = method.getBlock();
+ builder.append(block.getText().substring(1));
+ final GrVariableDeclaration variableDeclaration =
+ GroovyPsiElementFactory.getInstance(method.getProject()).createFieldDeclarationFromText(builder.toString());
+ method.replace(variableDeclaration);
+
+ for (GrReferenceExpression element : usagesToConvert) {
+ final PsiElement qualifier = element.getQualifier();
+ final StringBuilder text = new StringBuilder(qualifier.getText());
+ element.setQualifierExpression(null);
+ text.append('.').append(element.getText());
+ element.replace(factory.createExpressionFromText(text.toString()));
+ }
+ }
+ });
}
private static class MyPredicate implements PsiElementPredicate {
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrReferenceExpression.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrReferenceExpression.java
index a82661b8a4fc..65c6bb116e96 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrReferenceExpression.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/api/statements/expressions/GrReferenceExpression.java
@@ -43,6 +43,8 @@ public interface GrReferenceExpression extends GrExpression, GrReferenceElement,
boolean hasAt();
+ boolean hasMemberPointer();
+
void replaceDotToken(PsiElement newDotToken);
//not caching!
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java
index 31e39245d10f..b80e88fcf4ba 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java
@@ -733,6 +733,11 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements
return findChildByType(GroovyTokenTypes.mAT) != null;
}
+ @Override
+ public boolean hasMemberPointer() {
+ return findChildByType(GroovyTokenTypes.mMEMBER_POINTER) != null;
+ }
+
public boolean isReferenceTo(PsiElement element) {
return getManager().areElementsEquivalent(element, GroovyTargetElementEvaluator.correctSearchTargets(resolve()));
}
diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/intentions/ConvertMethodToClosureTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/intentions/ConvertMethodToClosureTest.java
index da8fd998e6e2..2f1df8411203 100644
--- a/plugins/groovy/test/org/jetbrains/plugins/groovy/intentions/ConvertMethodToClosureTest.java
+++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/intentions/ConvertMethodToClosureTest.java
@@ -51,6 +51,10 @@ public class ConvertMethodToClosureTest extends GrIntentionTestCase {
doClosureToMethodTest();
}
+ public void testMethodToClosureWithMemberPointer() {
+ doMethodToClosureTest();
+ }
+
private void doClosureToMethodTest() {
doTest(GroovyIntentionsBundle.message("convert.closure.to.method.intention.name"), true);
}
diff --git a/plugins/groovy/testdata/intentions/convertMethodToClosure/MethodToClosureWithMemberPointer.groovy b/plugins/groovy/testdata/intentions/convertMethodToClosure/MethodToClosureWithMemberPointer.groovy
new file mode 100644
index 000000000000..670abc75cef4
--- /dev/null
+++ b/plugins/groovy/testdata/intentions/convertMethodToClosure/MethodToClosureWithMemberPointer.groovy
@@ -0,0 +1,12 @@
+class X {
+ def foo(def it = null) {print it}
+
+ def bar() {
+ print this.&foo
+ }
+}
+
+final X x = new X()
+print x.&foo
+x.foo(2)
+
diff --git a/plugins/groovy/testdata/intentions/convertMethodToClosure/MethodToClosureWithMemberPointer_after.groovy b/plugins/groovy/testdata/intentions/convertMethodToClosure/MethodToClosureWithMemberPointer_after.groovy
new file mode 100644
index 000000000000..95bf6c71ad25
--- /dev/null
+++ b/plugins/groovy/testdata/intentions/convertMethodToClosure/MethodToClosureWithMemberPointer_after.groovy
@@ -0,0 +1,12 @@
+class X {
+ def foo = {def it = null -> print it}
+
+ def bar() {
+ print this.foo
+ }
+}
+
+final X x = new X()
+print x.foo
+x.foo(2)
+