From 1053a968725569e0229ae90effdad372f66a8cad Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Wed, 10 Dec 2014 20:24:41 +0100 Subject: [PATCH] introduce code block parameter: extract method call with conditional exit --- .../extractMethod/ExtractMethodProcessor.java | 4 +- .../IntroduceParameterHandler.java | 69 +++++++++++++------ .../afterIntConsumer.java | 2 +- .../afterIntConsumerFromIfStatement.java | 2 +- .../afterIntPredicateConditionalExit.java | 23 +++++++ .../afterSampleRunnable.java | 2 +- .../beforeIntPredicateConditionalExit.java | 16 +++++ .../IntroduceFunctionalParameterTest.java | 14 +++- 8 files changed, 103 insertions(+), 29 deletions(-) create mode 100644 java/java-tests/testData/refactoring/introduceFunctionalParameter/afterIntPredicateConditionalExit.java create mode 100644 java/java-tests/testData/refactoring/introduceFunctionalParameter/beforeIntPredicateConditionalExit.java diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java index 7e4a5b46028b..6b3e2e709d13 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java @@ -129,8 +129,8 @@ public class ExtractMethodProcessor implements MatchProvider { protected PsiStatement myFirstExitStatementCopy; private PsiMethod myExtractedMethod; private PsiMethodCallExpression myMethodCall; - private boolean myNullConditionalCheck = false; - private boolean myNotNullConditionalCheck = false; + protected boolean myNullConditionalCheck = false; + protected boolean myNotNullConditionalCheck = false; private Nullness myNullness; public ExtractMethodProcessor(Project project, diff --git a/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterHandler.java b/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterHandler.java index fec92750c507..fe04b0211b7f 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceParameter/IntroduceParameterHandler.java @@ -47,6 +47,7 @@ import com.intellij.openapi.ui.popup.JBPopupAdapter; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.ui.popup.LightweightWindowEvent; import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.Pass; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.wm.IdeFocusManager; @@ -529,9 +530,15 @@ public class IntroduceParameterHandler extends IntroduceHandlerBase { return false; } - final MyExtractMethodProcessor processor = new MyExtractMethodProcessor(project, editor, elements); + final PsiFile copy = PsiFileFactory.getInstance(project) + .createFileFromText(file.getName(), file.getFileType(), file.getText(), file.getModificationStamp(), false); + + final PsiElement[] elementsCopy = CodeInsightUtil.findStatementsInRange(copy, + elements[0].getTextRange().getStartOffset(), + elements[elements.length - 1].getTextRange().getEndOffset()); + final MyExtractMethodProcessor processor = new MyExtractMethodProcessor(project, editor, elementsCopy); try { - processor.prepare(); + if (!processor.prepare()) return false; processor.showDialog(); final PsiMethod emptyMethod = processor.generateEmptyMethod("name"); @@ -542,7 +549,7 @@ public class IntroduceParameterHandler extends IntroduceHandlerBase { if (types.size() == 1 || ApplicationManager.getApplication().isUnitTestMode()) { final PsiType next = types.iterator().next(); - functionalInterfaceSelected(next, enclosingMethods, project, editor, processor); + functionalInterfaceSelected(next, enclosingMethods, project, editor, processor, elements); } else { final Map classes = new LinkedHashMap(); @@ -550,11 +557,11 @@ public class IntroduceParameterHandler extends IntroduceHandlerBase { classes.put(PsiUtil.resolveClassInType(type), type); } final PsiClass[] psiClasses = classes.keySet().toArray(new PsiClass[classes.size()]); - NavigationUtil.getPsiElementPopup(psiClasses, new PsiClassListCellRenderer(), "Choose From Applicable Functional Interfaces", + NavigationUtil.getPsiElementPopup(psiClasses, new PsiClassListCellRenderer(), "Choose Applicable Functional Interface", new PsiElementProcessor() { @Override public boolean execute(@NotNull PsiClass psiClass) { - functionalInterfaceSelected(classes.get(psiClass), enclosingMethods, project, editor, processor); + functionalInterfaceSelected(classes.get(psiClass), enclosingMethods, project, editor, processor, elements); return true; } }).showInBestPositionFor(editor); @@ -571,14 +578,15 @@ public class IntroduceParameterHandler extends IntroduceHandlerBase { } private void functionalInterfaceSelected(final PsiType selectedType, - final List enclosingMethods, + final List enclosingMethods, final Project project, final Editor editor, - final MyExtractMethodProcessor processor) { + final MyExtractMethodProcessor processor, + final PsiElement[] elements) { final PairConsumer consumer = new PairConsumer() { @Override public void consume(PsiMethod methodToIntroduceParameter, PsiMethod methodToSearchFor) { - introduceWrappedCodeBlockParameter(methodToIntroduceParameter, methodToSearchFor, editor, project, selectedType, processor); + introduceWrappedCodeBlockParameter(methodToIntroduceParameter, methodToSearchFor, editor, project, selectedType, processor, elements); } }; chooseMethodToIntroduceParameter(editor, enclosingMethods, consumer); @@ -588,17 +596,29 @@ public class IntroduceParameterHandler extends IntroduceHandlerBase { PsiMethod methodToSearchFor, Editor editor, final Project project, final PsiType selectedType, - final MyExtractMethodProcessor processor) { - final PsiElement[] elements = processor.getElements(); - final PsiElement commonParent = PsiTreeUtil.findCommonParent(elements); - final RangeMarker marker = editor.getDocument().createRangeMarker(elements[0].getTextOffset(), - elements[elements.length - 1].getTextRange().getEndOffset()); + final MyExtractMethodProcessor processor, + final PsiElement[] elements) { + final PsiElement commonParent = elements.length > 1 ? PsiTreeUtil.findCommonParent(elements) : elements[0].getParent(); + if (commonParent == null) { + LOG.error("Should have common parent:" + Arrays.toString(elements)); + return; + } + final RangeMarker marker = editor.getDocument().createRangeMarker(commonParent.getTextRange()); + + final PsiElement[] copyElements = processor.getElements(); + final PsiElement containerCopy = copyElements.length > 1 ? PsiTreeUtil.findCommonParent(copyElements) : copyElements[0].getParent(); + if (containerCopy == null) { + LOG.error("Should have common parent:" + Arrays.toString(copyElements)); + return; + } + final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(selectedType); final PsiClass wrapperClass = resolveResult.getElement(); LOG.assertTrue(wrapperClass != null); final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); - final Ref methodCallText = new Ref(); + final Ref suffixText = new Ref(); + final Ref prefixText = new Ref(); final Ref methodText = new Ref(); WriteCommandAction.runWriteCommandAction(project, new Runnable() { @Override @@ -623,10 +643,8 @@ public class IntroduceParameterHandler extends IntroduceHandlerBase { methodText.set(extractedMethod.getText()); final PsiMethodCallExpression methodCall = processor.getMethodCall(); - methodCallText.set(methodCall.getText()); - - methodCall.delete(); - extractedMethod.delete(); + prefixText.set(containerCopy.getText().substring(0, methodCall.getTextRange().getStartOffset() - containerCopy.getTextRange().getStartOffset())); + suffixText.set("." + methodCall.getText() + containerCopy.getText().substring(methodCall.getTextRange().getEndOffset() - containerCopy.getTextRange().getStartOffset())); } }); @@ -637,9 +655,10 @@ public class IntroduceParameterHandler extends IntroduceHandlerBase { expression = (PsiExpression)JavaCodeStyleManager.getInstance(project).shortenClassReferences(expression); expression.putUserData(ElementToWorkOn.PARENT, commonParent); - expression.putUserData(ElementToWorkOn.SUFFIX, "." + methodCallText.get() + ";"); - + expression.putUserData(ElementToWorkOn.PREFIX, prefixText.get()); + expression.putUserData(ElementToWorkOn.SUFFIX, suffixText.get()); expression.putUserData(ElementToWorkOn.TEXT_RANGE, marker); + new Introducer(project, expression, null, editor) .introduceParameter(methodToIntroduceParameter, methodToSearchFor); } @@ -664,7 +683,15 @@ public class IntroduceParameterHandler extends IntroduceHandlerBase { } @Override - protected void deleteExtracted() throws IncorrectOperationException {} + public boolean prepare(@Nullable Pass pass) throws PrepareFailedException { + final boolean prepare = super.prepare(pass); + if (prepare) { + if (myNotNullConditionalCheck || myNullConditionalCheck) { + return false; + } + } + return prepare; + } private class MyAbstractExtractDialog implements AbstractExtractDialog { @Override diff --git a/java/java-tests/testData/refactoring/introduceFunctionalParameter/afterIntConsumer.java b/java/java-tests/testData/refactoring/introduceFunctionalParameter/afterIntConsumer.java index 8def3e7ca47d..6f30d35ed4bd 100644 --- a/java/java-tests/testData/refactoring/introduceFunctionalParameter/afterIntConsumer.java +++ b/java/java-tests/testData/refactoring/introduceFunctionalParameter/afterIntConsumer.java @@ -1,7 +1,7 @@ import java.util.function.Consumer; class Test { - void bar() { + void bar() { foo(1, new Consumer() { public void accept(Integer i) { System.out.println(i); diff --git a/java/java-tests/testData/refactoring/introduceFunctionalParameter/afterIntConsumerFromIfStatement.java b/java/java-tests/testData/refactoring/introduceFunctionalParameter/afterIntConsumerFromIfStatement.java index 4c3001b58046..38a00ad16528 100644 --- a/java/java-tests/testData/refactoring/introduceFunctionalParameter/afterIntConsumerFromIfStatement.java +++ b/java/java-tests/testData/refactoring/introduceFunctionalParameter/afterIntConsumerFromIfStatement.java @@ -1,7 +1,7 @@ import java.util.function.Consumer; class Test { - void bar() { + void bar() { foo(1, new Consumer() { public void accept(Integer i) { System.out.println(i); diff --git a/java/java-tests/testData/refactoring/introduceFunctionalParameter/afterIntPredicateConditionalExit.java b/java/java-tests/testData/refactoring/introduceFunctionalParameter/afterIntPredicateConditionalExit.java new file mode 100644 index 000000000000..656f25bb31df --- /dev/null +++ b/java/java-tests/testData/refactoring/introduceFunctionalParameter/afterIntPredicateConditionalExit.java @@ -0,0 +1,23 @@ +import java.util.function.IntPredicate; + +class Test { + void bar() { + foo(1, new IntPredicate() { + public boolean test(int i) { + if (i > 0) { + System.out.println(i); + System.out.println(i); + return true; + } + return false; + } + }); + } + + void foo(int i, IntPredicate anObject) { + + if (anObject.test(i)) return; + + System.out.println("Hi"); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/introduceFunctionalParameter/afterSampleRunnable.java b/java/java-tests/testData/refactoring/introduceFunctionalParameter/afterSampleRunnable.java index bb7422991f9f..023e3829c3f3 100644 --- a/java/java-tests/testData/refactoring/introduceFunctionalParameter/afterSampleRunnable.java +++ b/java/java-tests/testData/refactoring/introduceFunctionalParameter/afterSampleRunnable.java @@ -1,5 +1,5 @@ class Test { - void bar() { + void bar() { foo(new Runnable() { public void run() { System.out.println(""); diff --git a/java/java-tests/testData/refactoring/introduceFunctionalParameter/beforeIntPredicateConditionalExit.java b/java/java-tests/testData/refactoring/introduceFunctionalParameter/beforeIntPredicateConditionalExit.java new file mode 100644 index 000000000000..69c0452e1ccf --- /dev/null +++ b/java/java-tests/testData/refactoring/introduceFunctionalParameter/beforeIntPredicateConditionalExit.java @@ -0,0 +1,16 @@ +class Test { + void bar() { + foo(1); + } + + void foo(int i) { + + if (i > 0) { + System.out.println(i); + System.out.println(i); + return; + } + + System.out.println("Hi"); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceFunctionalParameterTest.java b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceFunctionalParameterTest.java index 4f91fa359f2d..6da97834656b 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/IntroduceFunctionalParameterTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/IntroduceFunctionalParameterTest.java @@ -26,15 +26,19 @@ import org.jetbrains.annotations.NotNull; @TestDataPath("$CONTENT_ROOT/testData") public class IntroduceFunctionalParameterTest extends LightRefactoringTestCase { public void testSampleRunnable() throws Exception { - doTest(null); + doTest(); } public void testIntConsumer() throws Exception { - doTest(null); + doTest(); } public void testIntConsumerFromIfStatement() throws Exception { - doTest(null); + doTest(); + } + + public void testIntPredicateConditionalExit() throws Exception { + doTest(); } @NotNull @@ -53,6 +57,10 @@ public class IntroduceFunctionalParameterTest extends LightRefactoringTestCase return IdeaTestUtil.getMockJdk18(); } + private void doTest() { + doTest(null); + } + private void doTest(String conflict) { boolean enabled = true; try {