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 e63b3751e425..44d1c2f9da10 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/extractMethod/ExtractMethodProcessor.java @@ -575,10 +575,16 @@ public class ExtractMethodProcessor implements MatchProvider { chooseAnchor(); - int col = myEditor.getCaretModel().getLogicalPosition().column; - int line = myEditor.getCaretModel().getLogicalPosition().line; - LogicalPosition pos = new LogicalPosition(0, 0); - myEditor.getCaretModel().moveToLogicalPosition(pos); + LogicalPosition pos1; + if (myEditor != null) { + int col = myEditor.getCaretModel().getLogicalPosition().column; + int line = myEditor.getCaretModel().getLogicalPosition().line; + pos1 = new LogicalPosition(line, col); + LogicalPosition pos = new LogicalPosition(0, 0); + myEditor.getCaretModel().moveToLogicalPosition(pos); + } else { + pos1 = null; + } final SearchScope processConflictsScope = myMethodVisibility.equals(PsiModifier.PRIVATE) ? new LocalSearchScope(myTargetClass) : @@ -610,12 +616,13 @@ public class ExtractMethodProcessor implements MatchProvider { ApplicationManager.getApplication().runWriteAction(extract); } - LogicalPosition pos1 = new LogicalPosition(line, col); - myEditor.getCaretModel().moveToLogicalPosition(pos1); - int offset = myMethodCall.getMethodExpression().getTextRange().getStartOffset(); - myEditor.getCaretModel().moveToOffset(offset); - myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); - myEditor.getSelectionModel().removeSelection(); + if (myEditor != null) { + myEditor.getCaretModel().moveToLogicalPosition(pos1); + int offset = myMethodCall.getMethodExpression().getTextRange().getStartOffset(); + myEditor.getCaretModel().moveToOffset(offset); + myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); + myEditor.getSelectionModel().removeSelection(); + } } private void doExtract() throws IncorrectOperationException { diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractLightMethodObjectHandler.java b/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractLightMethodObjectHandler.java index c5ee560434a5..30eb9035d419 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractLightMethodObjectHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractLightMethodObjectHandler.java @@ -16,18 +16,27 @@ package com.intellij.refactoring.extractMethodObject; import com.intellij.codeInsight.CodeInsightUtil; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Document; -import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.RangeMarker; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; +import com.intellij.psi.controlFlow.*; import com.intellij.refactoring.extractMethod.AbstractExtractDialog; import com.intellij.refactoring.extractMethod.InputVariables; +import com.intellij.refactoring.extractMethod.PrepareFailedException; +import com.intellij.refactoring.util.RefactoringUtil; import com.intellij.refactoring.util.VariableData; +import com.intellij.util.Function; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.List; + public class ExtractLightMethodObjectHandler { private static final Logger LOG = Logger.getInstance("#" + ExtractLightMethodObjectHandler.class.getName()); @@ -51,36 +60,74 @@ public class ExtractLightMethodObjectHandler { @Nullable public static ExtractedData extractLightMethodObject(final Project project, - final Editor editor, final PsiFile file, - final PsiElement[] elements, - final String methodName) { - if (elements == null || elements.length == 0) { + @NotNull final PsiCodeFragment fragment, + final String methodName) throws PrepareFailedException { + final PsiElement[] elements = fragment.getChildren(); + if (elements.length == 0) { return null; } final PsiFile copy = PsiFileFactory.getInstance(project) .createFileFromText(file.getName(), file.getFileType(), file.getText(), file.getModificationStamp(), true); - final PsiElement[] elementsCopy = new PsiElement[elements.length]; - for (int i = 0; i < elements.length; i++) { - PsiElement element = elements[i]; - final TextRange textRange = element.getTextRange(); - elementsCopy[i] = CodeInsightUtil.findElementInRange(copy, textRange.getStartOffset(), textRange.getEndOffset(), element.getClass()); + final PsiElement originalContext = fragment.getContext(); + if (originalContext == null) { + return null; } + final TextRange range = originalContext.getTextRange(); + final PsiElement originalAnchor = + CodeInsightUtil.findElementInRange(copy, range.getStartOffset(), range.getEndOffset(), originalContext.getClass()); + //todo before this or super, not found etc + final PsiElement anchor = RefactoringUtil.getParentStatement(originalAnchor, false); + final PsiElement[] elementsCopy = new PsiElement[elements.length]; + final PsiElement container = anchor.getParent(); + elementsCopy[0] = ApplicationManager.getApplication().runWriteAction(new Computable() { + @Override + public PsiElement compute() { + return container.addRangeAfter(elements[0], elements[elements.length - 1], anchor); + } + }); + for (int i = 1; i < elements.length; i++) { + elementsCopy[i] = elementsCopy[i - 1].getNextSibling(); + } + + final ControlFlow controlFlow; + try { + controlFlow = ControlFlowFactory.getInstance(project).getControlFlow(container, AllVariablesControlFlowPolicy.getInstance()); + } + catch (AnalysisCanceledException e) { + return null; + } + + final List variables = ControlFlowUtil.getUsedVariables(controlFlow, 0, controlFlow.getSize()); + + final String outputVariables = StringUtil.join(variables, new Function() { + @Override + public String fun(PsiVariable variable) { + return "\"variable: \" + " + variable.getName(); + } + }, " +"); + final PsiStatement outStatement = JavaPsiFacade.getElementFactory(project).createStatementFromText("System.out.println(" + outputVariables + ");", anchor); + + ApplicationManager.getApplication().runWriteAction(new Runnable() { + public void run() { + container.addAfter(outStatement, elementsCopy[elementsCopy.length - 1]); + } + }); final Document document = PsiDocumentManager.getInstance(project).getDocument(copy); LOG.assertTrue(document != null); - final int startOffset = elements[0].getTextRange().getStartOffset(); - final int endOffset = elements[elements.length - 1].getTextRange().getEndOffset(); + final int startOffset = elementsCopy[0].getTextRange().getStartOffset(); + final int endOffset = elementsCopy[elementsCopy.length - 1].getTextRange().getEndOffset(); final RangeMarker callSiteMarker = document.createRangeMarker(startOffset, endOffset); callSiteMarker.setGreedyToLeft(true); callSiteMarker.setGreedyToRight(true); try { - final ExtractMethodObjectProcessor extractMethodObjectProcessor = new ExtractMethodObjectProcessor(project, editor, elementsCopy, "") { + final ExtractMethodObjectProcessor extractMethodObjectProcessor = new ExtractMethodObjectProcessor(project, null, elementsCopy, "") { @Override protected AbstractExtractDialog createExtractMethodObjectDialog(MyExtractMethodProcessor processor) { return new LightExtractMethodObjectDialog(this, methodName); @@ -88,7 +135,7 @@ public class ExtractLightMethodObjectHandler { }; extractMethodObjectProcessor.getExtractProcessor().setShowErrorDialogs(false); - ExtractMethodObjectHandler.extractMethodObject(project, editor, file, extractMethodObjectProcessor); + ExtractMethodObjectHandler.extractMethodObject(project, null, extractMethodObjectProcessor); final String generatedCall = document.getText(new TextRange(callSiteMarker.getStartOffset(), callSiteMarker.getEndOffset())); return new ExtractedData(generatedCall, extractMethodObjectProcessor.getInnerClass()); diff --git a/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectHandler.java b/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectHandler.java index b09a02cfd561..8004dcf77578 100644 --- a/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectHandler.java +++ b/java/java-impl/src/com/intellij/refactoring/extractMethodObject/ExtractMethodObjectHandler.java @@ -20,12 +20,10 @@ */ package com.intellij.refactoring.extractMethodObject; -import com.intellij.codeInsight.CodeInsightUtil; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.RangeMarker; import com.intellij.openapi.editor.ScrollType; @@ -37,12 +35,9 @@ import com.intellij.psi.impl.source.PostprocessReformattingAspect; import com.intellij.refactoring.HelpID; import com.intellij.refactoring.RefactoringActionHandler; import com.intellij.refactoring.RefactoringBundle; -import com.intellij.refactoring.extractMethod.AbstractExtractDialog; import com.intellij.refactoring.extractMethod.ExtractMethodHandler; -import com.intellij.refactoring.extractMethod.InputVariables; import com.intellij.refactoring.extractMethod.PrepareFailedException; import com.intellij.refactoring.util.CommonRefactoringUtil; -import com.intellij.refactoring.util.VariableData; import com.intellij.refactoring.util.duplicates.DuplicatesImpl; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; @@ -69,20 +64,18 @@ public class ExtractMethodObjectHandler implements RefactoringActionHandler { return; } - extractMethodObject(project, editor, file, new ExtractMethodObjectProcessor(project, editor, elements, "")); - } - - static void extractMethodObject(Project project, Editor editor, PsiFile file, ExtractMethodObjectProcessor processor) { - final ExtractMethodObjectProcessor.MyExtractMethodProcessor extractProcessor = processor.getExtractProcessor(); try { - if (!extractProcessor.prepare()) return; + extractMethodObject(project, editor, new ExtractMethodObjectProcessor(project, editor, elements, "")); } catch (PrepareFailedException e) { CommonRefactoringUtil.showErrorHint(project, editor, e.getMessage(), ExtractMethodObjectProcessor.REFACTORING_NAME, HelpID.EXTRACT_METHOD_OBJECT); ExtractMethodHandler.highlightPrepareError(e, file, editor, project); - return; } + } + static void extractMethodObject(Project project, Editor editor, ExtractMethodObjectProcessor processor) throws PrepareFailedException { + final ExtractMethodObjectProcessor.MyExtractMethodProcessor extractProcessor = processor.getExtractProcessor(); + if (!extractProcessor.prepare()) return; if (!CommonRefactoringUtil.checkReadOnlyStatus(project, extractProcessor.getTargetClass().getContainingFile())) return; if (extractProcessor.showDialog()) { run(project, editor, processor, extractProcessor); @@ -90,11 +83,16 @@ public class ExtractMethodObjectHandler implements RefactoringActionHandler { } public static void run(@NotNull final Project project, - @NotNull final Editor editor, + final Editor editor, @NotNull final ExtractMethodObjectProcessor processor, @NotNull final ExtractMethodObjectProcessor.MyExtractMethodProcessor extractProcessor) { - final int offset = editor.getCaretModel().getOffset(); - final RangeMarker marker = editor.getDocument().createRangeMarker(new TextRange(offset, offset)); + final RangeMarker marker; + if (editor != null) { + final int offset = editor.getCaretModel().getOffset(); + marker = editor.getDocument().createRangeMarker(new TextRange(offset, offset)); + } else { + marker = null; + } CommandProcessor.getInstance().executeCommand(project, new Runnable() { public void run() { PostprocessReformattingAspect.getInstance(project).postponeFormattingInside(new Runnable() { @@ -119,7 +117,9 @@ public class ExtractMethodObjectHandler implements RefactoringActionHandler { if (processor.isCreateInnerClass()) { processor.moveUsedMethodsToInner(); PsiDocumentManager.getInstance(project).commitAllDocuments(); - DuplicatesImpl.processDuplicates(extractProcessor, project, editor); + if (editor != null) { + DuplicatesImpl.processDuplicates(extractProcessor, project, editor); + } } ApplicationManager.getApplication().runWriteAction(new Runnable() { @Override @@ -134,9 +134,11 @@ public class ExtractMethodObjectHandler implements RefactoringActionHandler { }); } }, ExtractMethodObjectProcessor.REFACTORING_NAME, ExtractMethodObjectProcessor.REFACTORING_NAME); - editor.getCaretModel().moveToOffset(marker.getStartOffset()); - marker.dispose(); - editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); + if (editor != null) { + editor.getCaretModel().moveToOffset(marker.getStartOffset()); + marker.dispose(); + editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); + } } public void invoke(@NotNull final Project project, @NotNull final PsiElement[] elements, final DataContext dataContext) { diff --git a/java/java-tests/testData/refactoring/extractMethodObject4Debugger/SimpleGeneration.java b/java/java-tests/testData/refactoring/extractMethodObject4Debugger/SimpleGeneration.java index 178a4844ef5f..873f2205e1af 100644 --- a/java/java-tests/testData/refactoring/extractMethodObject4Debugger/SimpleGeneration.java +++ b/java/java-tests/testData/refactoring/extractMethodObject4Debugger/SimpleGeneration.java @@ -1,7 +1,5 @@ class Sample { void foo() { - int i = 0; - int j = 0; - System.out.println(i + j); + System.out.println("hello world"); } } \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodObject4DebuggerTest.java b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodObject4DebuggerTest.java index 64e355126e2f..bc6c1befaa12 100644 --- a/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodObject4DebuggerTest.java +++ b/java/java-tests/testSrc/com/intellij/refactoring/ExtractMethodObject4DebuggerTest.java @@ -21,10 +21,9 @@ package com.intellij.refactoring; import com.intellij.JavaTestUtil; -import com.intellij.codeInsight.CodeInsightUtil; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.projectRoots.Sdk; -import com.intellij.psi.PsiClass; -import com.intellij.psi.PsiElement; +import com.intellij.psi.*; import com.intellij.refactoring.extractMethodObject.ExtractLightMethodObjectHandler; import com.intellij.testFramework.IdeaTestUtil; import org.jetbrains.annotations.NotNull; @@ -36,16 +35,14 @@ public class ExtractMethodObject4DebuggerTest extends LightRefactoringTestCase { return JavaTestUtil.getJavaTestDataPath(); } - private void doTest(String expectedCallSite, String expectedClass) throws Exception { + private void doTest(String evaluatedText, String expectedCallSite, String expectedClass) throws Exception { final String testName = getTestName(false); configureByFile("/refactoring/extractMethodObject4Debugger/" + testName + ".java"); - int startOffset = getEditor().getSelectionModel().getSelectionStart(); - int endOffset = getEditor().getSelectionModel().getSelectionEnd(); - PsiElement[] elements = CodeInsightUtil.findStatementsInRange(getFile(), startOffset, endOffset); - assertTrue(elements.length > 0); - + final int offset = getEditor().getCaretModel().getOffset(); + final PsiElement context = getFile().findElementAt(offset); + final JavaCodeFragment fragment = JavaCodeFragmentFactory.getInstance(getProject()).createCodeBlockCodeFragment(evaluatedText, context, false); final ExtractLightMethodObjectHandler.ExtractedData extractedData = - ExtractLightMethodObjectHandler.extractLightMethodObject(getProject(), getEditor(), getFile(), elements, "test"); + ExtractLightMethodObjectHandler.extractLightMethodObject(getProject(), getFile(), fragment, "test"); assertNotNull(extractedData); assertEquals(expectedCallSite, extractedData.getGeneratedCallText()); final PsiClass innerClass = extractedData.getGeneratedInnerClass(); @@ -53,7 +50,7 @@ public class ExtractMethodObject4DebuggerTest extends LightRefactoringTestCase { } public void testSimpleGeneration() throws Exception { - doTest(" Test test = new Test().invoke();\n" + + doTest("int i = 0; int j = 0;", "Test test = new Test().invoke();\n" + " int i = test.getI();\n" + " int j = test.getJ();",