introduce code block parameter: extract method call with conditional exit

This commit is contained in:
Anna Kozlova
2014-12-11 11:16:44 +01:00
parent c6fbcb86a3
commit 1053a96872
8 changed files with 103 additions and 29 deletions
@@ -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,
@@ -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<PsiClass, PsiType> classes = new LinkedHashMap<PsiClass, PsiType>();
@@ -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<PsiClass>() {
@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<PsiMethod> enclosingMethods,
final List<PsiMethod> enclosingMethods,
final Project project,
final Editor editor,
final MyExtractMethodProcessor processor) {
final MyExtractMethodProcessor processor,
final PsiElement[] elements) {
final PairConsumer<PsiMethod, PsiMethod> consumer = new PairConsumer<PsiMethod, PsiMethod>() {
@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<String> methodCallText = new Ref<String>();
final Ref<String> suffixText = new Ref<String>();
final Ref<String> prefixText = new Ref<String>();
final Ref<String> methodText = new Ref<String>();
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<ExtractMethodProcessor> pass) throws PrepareFailedException {
final boolean prepare = super.prepare(pass);
if (prepare) {
if (myNotNullConditionalCheck || myNullConditionalCheck) {
return false;
}
}
return prepare;
}
private class MyAbstractExtractDialog implements AbstractExtractDialog {
@Override
@@ -1,7 +1,7 @@
import java.util.function.Consumer;
class Test {
void bar() {
void bar() {
foo(1, new Consumer<Integer>() {
public void accept(Integer i) {
System.out.println(i);
@@ -1,7 +1,7 @@
import java.util.function.Consumer;
class Test {
void bar() {
void bar() {
foo(1, new Consumer<Integer>() {
public void accept(Integer i) {
System.out.println(i);
@@ -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");
}
}
@@ -1,5 +1,5 @@
class Test {
void bar() {
void bar() {
foo(new Runnable() {
public void run() {
System.out.println("");
@@ -0,0 +1,16 @@
class Test {
void bar() {
foo(1);
}
void foo(int i) {
<selection>
if (i > 0) {
System.out.println(i);
System.out.println(i);
return;
}
</selection>
System.out.println("Hi");
}
}
@@ -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 {