diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/ApplicationStatementUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/ApplicationStatementUtil.java new file mode 100644 index 000000000000..e6873b1a0882 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/ApplicationStatementUtil.java @@ -0,0 +1,104 @@ +/* + * 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.lang.psi.impl; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrApplicationStatement; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCommandArgumentList; +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.GrMethodCallExpression; + +/** + * @author Max Medvedev + */ +public class ApplicationStatementUtil { + private static final Logger LOG = Logger.getInstance(ApplicationStatementUtil.class); + + public static GrExpression convertToMethodCallExpression(GrExpression expr) { + final Project project = expr.getProject(); + final GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(project); + + boolean copied = false; + if (expr instanceof GrApplicationStatement) { + expr = convertAppInternal(factory, (GrApplicationStatement)expr); + copied = true; + } + + if (expr instanceof GrReferenceExpression && + ((GrReferenceExpression)expr).getDotToken() == null && + ((GrReferenceExpression)expr).getQualifier() != null) { + expr = convertRefInternal(factory, ((GrReferenceExpression)expr)); + copied = true; + } + + + if (!shouldManage(expr)) return expr; + if (!copied) expr = (GrExpression)expr.copy(); + + for (PsiElement child = expr.getFirstChild(); child != null; child = child.getFirstChild()) { + if (child instanceof GrApplicationStatement) { + child = child.replace(convertAppInternal(factory, (GrApplicationStatement)child)); + } + else if (child instanceof GrReferenceExpression && + ((GrReferenceExpression)child).getDotToken() == null && + ((GrReferenceExpression)child).getQualifier() != null) { + child = child.replace(convertRefInternal(factory, ((GrReferenceExpression)child))); + } + } + + return expr; + } + + private static boolean shouldManage(GrExpression expr) { + for (PsiElement child = expr.getFirstChild(); child != null; child = child.getFirstChild()) { + if (child instanceof GrApplicationStatement) { + return true; + } + else if (child instanceof GrReferenceExpression && + ((GrReferenceExpression)child).getDotToken() == null && + ((GrReferenceExpression)child).getQualifier() != null) { + return true; + } + } + return false; + } + + private static GrReferenceExpression convertRefInternal(GroovyPsiElementFactory factory, GrReferenceExpression ref) { + ref.addAfter(factory.createDotToken("."), ref.getQualifier()); + return ref; + } + + private static GrMethodCallExpression convertAppInternal(GroovyPsiElementFactory factory, GrApplicationStatement app) { + final GrCommandArgumentList list = app.getArgumentList(); + + final GrMethodCallExpression prototype = (GrMethodCallExpression)factory.createExpressionFromText("foo()"); + prototype.getInvokedExpression().replace(app.getInvokedExpression()); + final GrArgumentList pList = prototype.getArgumentList(); + LOG.assertTrue(pList != null); + + final PsiElement anchor = pList.getRightParen(); + for (PsiElement ch = list.getFirstChild(); ch != null; ch = ch.getNextSibling()) { + pList.addBefore(ch, anchor); + } + + return prototype; + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/PsiImplUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/PsiImplUtil.java index fd65881d29d5..f837f3687ec3 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/PsiImplUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/PsiImplUtil.java @@ -110,16 +110,15 @@ public class PsiImplUtil { private static boolean isAfterIdentifier(PsiElement el) { final PsiElement prev = GeeseUtil.getPreviousNonWhitespaceToken(el); - return prev != null && prev.getNode().getElementType() == GroovyTokenTypes.mIDENT; + return prev != null && prev.getNode().getElementType() == mIDENT; } public static GrExpression replaceExpression(GrExpression oldExpr, GrExpression newExpr, boolean removeUnnecessaryParentheses) { PsiElement oldParent = oldExpr.getParent(); if (oldParent == null) throw new PsiInvalidElementAccessException(oldExpr); - if (newExpr instanceof GrApplicationStatement && !(oldExpr instanceof GrApplicationStatement)) { - GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(oldExpr.getProject()); - newExpr = factory.createMethodCallByAppCall(((GrApplicationStatement)newExpr)); + if (!(oldExpr instanceof GrApplicationStatement)) { + newExpr = ApplicationStatementUtil.convertToMethodCallExpression(newExpr); } // Remove unnecessary parentheses 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 309578d656a4..e6d501651b6a 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 @@ -30,13 +30,16 @@ 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.expressions.*; +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.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.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.ApplicationStatementUtil; 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.util.PsiUtil; @@ -311,21 +314,8 @@ public class ExtractUtil { 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()); - } + expr = ApplicationStatementUtil.convertToMethodCallExpression(expr); + buffer.append(expr.getText()); } else { buffer.append(expr != null ? expr.getText() : ""); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/GroovyExtractChooser.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/GroovyExtractChooser.java index f32ed727f3b3..4c8ee6d821bc 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/GroovyExtractChooser.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/extract/GroovyExtractChooser.java @@ -113,7 +113,9 @@ public class GroovyExtractChooser { throw new GrRefactoringError(GroovyRefactoringBundle.message("selected.block.should.represent.an.expression")); } - if (ExtractUtil.isSingleExpression(statements) && statement0.getParent() instanceof GrAssignmentExpression && ((GrAssignmentExpression)statement0.getParent()).getLValue()==statement0) { + if (ExtractUtil.isSingleExpression(statements) && + statement0.getParent() instanceof GrAssignmentExpression && + ((GrAssignmentExpression)statement0.getParent()).getLValue() == statement0) { throw new GrRefactoringError(GroovyRefactoringBundle.message("selected.expression.should.not.be.lvalue")); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/GrIntroduceHandlerBase.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/GrIntroduceHandlerBase.java index 85c2530e7aee..61cd64f3e1c8 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/GrIntroduceHandlerBase.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/refactoring/introduce/GrIntroduceHandlerBase.java @@ -107,9 +107,7 @@ public abstract class GrIntroduceHandlerBase"zxcvbn".substring 2 charAt(1) +} +foo() +''', ''' +void foo(Closure closure) { + def s = closure() +} +foo {return "zxcvbn".substring(2).charAt(1)} ''') } } 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.groovy similarity index 81% rename from plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extract/method/ExtractMethodTest.java rename to plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/extract/method/ExtractMethodTest.groovy index 522cb0214bf0..04fee16b1f12 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.groovy @@ -16,14 +16,13 @@ package org.jetbrains.plugins.groovy.refactoring.extract.method; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.psi.impl.source.PostprocessReformattingAspect; -import com.intellij.refactoring.util.CommonRefactoringUtil; -import org.jetbrains.plugins.groovy.GroovyFileType; -import org.jetbrains.plugins.groovy.LightGroovyTestCase; -import org.jetbrains.plugins.groovy.util.TestUtils; -import java.util.List; +import com.intellij.openapi.util.text.StringUtil +import com.intellij.psi.impl.source.PostprocessReformattingAspect +import com.intellij.refactoring.util.CommonRefactoringUtil +import org.jetbrains.plugins.groovy.GroovyFileType +import org.jetbrains.plugins.groovy.LightGroovyTestCase +import org.jetbrains.plugins.groovy.util.TestUtils /** * @author ilyas @@ -31,29 +30,29 @@ import java.util.List; public class ExtractMethodTest extends LightGroovyTestCase { @Override protected String getBasePath() { - return TestUtils.getTestDataPath() + "groovy/refactoring/extractMethod/"; + return TestUtils.testDataPath + "groovy/refactoring/extractMethod/"; } - private void doAntiTest(String errorMessage) throws Exception { + private void doAntiTest(String errorMessage) { GroovyExtractMethodHandler handler = configureFromText(readInput().get(0)); try { - handler.invoke(getProject(), myFixture.getEditor(), myFixture.getFile(), null); + handler.invoke(project, myFixture.editor, myFixture.file, null); assertTrue(false); } catch (CommonRefactoringUtil.RefactoringErrorHintException e) { - assertEquals(errorMessage, e.getLocalizedMessage()); + assertEquals(errorMessage, e.localizedMessage); } } private List readInput() { - return TestUtils.readInput(getTestDataPath() + getTestName(true) + ".test"); + return TestUtils.readInput(testDataPath + getTestName(true) + ".test"); } private void doTest() { final List data = readInput(); GroovyExtractMethodHandler handler = configureFromText(data.get(0)); - handler.invoke(getProject(), myFixture.getEditor(), myFixture.getFile(), null); - PostprocessReformattingAspect.getInstance(getProject()).doPostponedFormatting(); + handler.invoke(project, myFixture.editor, myFixture.file, null); + PostprocessReformattingAspect.getInstance(project).doPostponedFormatting(); myFixture.checkResult(StringUtil.trimEnd(data.get(1), "\n")); } @@ -64,7 +63,7 @@ public class ExtractMethodTest extends LightGroovyTestCase { fileText = TestUtils.removeEndMarker(fileText); myFixture.configureByText(GroovyFileType.GROOVY_FILE_TYPE, fileText); - myFixture.getEditor().getSelectionModel().setSelection(startOffset, endOffset); + myFixture.editor.selectionModel.setSelection(startOffset, endOffset); return new GroovyExtractMethodHandler(); } @@ -114,4 +113,5 @@ public class ExtractMethodTest extends LightGroovyTestCase { public void testWildCardReturnType() {doTest();} public void testParamChangedInsideExtractedMethod() {doTest();} + public void testTerribleAppStatement() {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 5de6df11474f..cf4e7c8249a5 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 @@ -295,4 +295,5 @@ public class GrIntroduceParameterTest extends LightCodeInsightFixtureTestCase { public void testClosureArgWithEmptyArgList() {doTest(IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_NONE, true, false);} public void testScriptMethod() {doTest(IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_NONE, true, false);} + public void testAppStatement() {doTest(IntroduceParameterRefactoring.REPLACE_FIELDS_WITH_GETTERS_NONE, false, false);} } diff --git a/plugins/groovy/testdata/groovy/refactoring/extractMethod/terribleAppStatement.test b/plugins/groovy/testdata/groovy/refactoring/extractMethod/terribleAppStatement.test new file mode 100644 index 000000000000..870a4066921a --- /dev/null +++ b/plugins/groovy/testdata/groovy/refactoring/extractMethod/terribleAppStatement.test @@ -0,0 +1,11 @@ +def foo() { + def s = "zxcvbn".substring 2 charAt(1) +} +----- +def foo() { + def s = testMethod() +} + +private char testMethod() { + return "zxcvbn".substring(2).charAt(1) +} \ No newline at end of file diff --git a/plugins/groovy/testdata/refactoring/introduceParameterGroovy/appStatement/AppStatementAfter.groovy b/plugins/groovy/testdata/refactoring/introduceParameterGroovy/appStatement/AppStatementAfter.groovy new file mode 100644 index 000000000000..5ed212b144fc --- /dev/null +++ b/plugins/groovy/testdata/refactoring/introduceParameterGroovy/appStatement/AppStatementAfter.groovy @@ -0,0 +1 @@ +new A().foo("zxcvbn".substring(2).charAt(1)) \ No newline at end of file diff --git a/plugins/groovy/testdata/refactoring/introduceParameterGroovy/appStatement/AppStatementBefore.groovy b/plugins/groovy/testdata/refactoring/introduceParameterGroovy/appStatement/AppStatementBefore.groovy new file mode 100644 index 000000000000..56e2e38b9a3d --- /dev/null +++ b/plugins/groovy/testdata/refactoring/introduceParameterGroovy/appStatement/AppStatementBefore.groovy @@ -0,0 +1 @@ +new A().foo() \ No newline at end of file diff --git a/plugins/groovy/testdata/refactoring/introduceParameterGroovy/appStatement/AppStatementMyClass.groovy b/plugins/groovy/testdata/refactoring/introduceParameterGroovy/appStatement/AppStatementMyClass.groovy new file mode 100644 index 000000000000..e4828d69722f --- /dev/null +++ b/plugins/groovy/testdata/refactoring/introduceParameterGroovy/appStatement/AppStatementMyClass.groovy @@ -0,0 +1,5 @@ +class A { + void foo() { + def s = "zxcvbn".substring(2).charAt(1) + } +} \ No newline at end of file diff --git a/plugins/groovy/testdata/refactoring/introduceParameterGroovy/incorrectArgumentList/IncorrectArgumentListAfter.groovy b/plugins/groovy/testdata/refactoring/introduceParameterGroovy/incorrectArgumentList/IncorrectArgumentListAfter.groovy index 853f4929faec..52ba1446be3e 100644 --- a/plugins/groovy/testdata/refactoring/introduceParameterGroovy/incorrectArgumentList/IncorrectArgumentListAfter.groovy +++ b/plugins/groovy/testdata/refactoring/introduceParameterGroovy/incorrectArgumentList/IncorrectArgumentListAfter.groovy @@ -1 +1 @@ -new A().foo(27 + 4.5) \ No newline at end of file +new A().foo(27+ 4.5) \ No newline at end of file