mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-06 03:21:12 +07:00
extract method object: wrap if/loop bodies in {} when needed (IDEA-92156)
This commit is contained in:
@@ -269,12 +269,39 @@ public class ExtractMethodObjectProcessor extends BaseRefactoringProcessor {
|
||||
final List<PsiLocalVariable> vars = new ArrayList<PsiLocalVariable>();
|
||||
final Map<PsiElement, PsiElement> replacementMap = new LinkedHashMap<PsiElement, PsiElement>();
|
||||
final List<PsiReturnStatement> returnStatements = new ArrayList<PsiReturnStatement>();
|
||||
body.accept(new JavaRecursiveElementWalkingVisitor() {
|
||||
@Override
|
||||
public void visitReturnStatement(PsiReturnStatement statement) {
|
||||
returnStatements.add(statement);
|
||||
}
|
||||
});
|
||||
if (myExtractProcessor.generatesConditionalExit()) {
|
||||
for (int i = 0; i < returnStatements.size() - 1; i++) {
|
||||
final PsiReturnStatement condition = returnStatements.get(i);
|
||||
final PsiElement container = condition.getParent();
|
||||
final PsiStatement resultStmt = myElementFactory.createStatementFromText("myResult = true;", container);
|
||||
if (!RefactoringUtil.isLoopOrIf(container)) {
|
||||
container.addBefore(resultStmt, condition);
|
||||
} else {
|
||||
RefactoringUtil.putStatementInLoopBody(resultStmt, container, condition);
|
||||
}
|
||||
}
|
||||
|
||||
LOG.assertTrue(!returnStatements.isEmpty());
|
||||
final PsiReturnStatement returnStatement = returnStatements.get(returnStatements.size() - 1);
|
||||
final PsiElement container = returnStatement.getParent();
|
||||
final PsiStatement resultStmt = myElementFactory.createStatementFromText("myResult = false;", container);
|
||||
if (!RefactoringUtil.isLoopOrIf(container)) {
|
||||
container.addBefore(resultStmt, returnStatement);
|
||||
} else {
|
||||
RefactoringUtil.putStatementInLoopBody(resultStmt, container, returnStatement);
|
||||
}
|
||||
}
|
||||
body.accept(new JavaRecursiveElementWalkingVisitor() {
|
||||
@Override
|
||||
public void visitReturnStatement(final PsiReturnStatement statement) {
|
||||
super.visitReturnStatement(statement);
|
||||
try {
|
||||
returnStatements.add(statement);
|
||||
replacementMap.put(statement, myElementFactory.createStatementFromText("return this;", statement));
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
@@ -324,17 +351,6 @@ public class ExtractMethodObjectProcessor extends BaseRefactoringProcessor {
|
||||
}
|
||||
});
|
||||
|
||||
if (myExtractProcessor.generatesConditionalExit()) {
|
||||
for (int i = 0; i < returnStatements.size() - 1; i++) {
|
||||
final PsiReturnStatement condition = returnStatements.get(i);
|
||||
condition.getParent().addBefore(myElementFactory.createStatementFromText("myResult = true;", condition), condition);
|
||||
}
|
||||
|
||||
LOG.assertTrue(!returnStatements.isEmpty());
|
||||
final PsiReturnStatement returnStatement = returnStatements.get(returnStatements.size() - 1);
|
||||
returnStatement.getParent().addBefore(myElementFactory.createStatementFromText("myResult = false;", returnStatement), returnStatement);
|
||||
}
|
||||
|
||||
for (PsiLocalVariable var : vars) {
|
||||
final String fieldName = var2FieldNames.get(var.getName());
|
||||
for (PsiReference reference : ReferencesSearch.search(var)) {
|
||||
|
||||
@@ -760,7 +760,7 @@ public abstract class BaseExpressionToFieldHandler extends IntroduceHandlerBase
|
||||
anchorElementHere = myAnchorElementIfOne;
|
||||
}
|
||||
assignStatement = createAssignment(myField, initializer, anchorElementHere, myParentClass);
|
||||
if (!IntroduceVariableBase.isLoopOrIf(anchorElementHere.getParent())) {
|
||||
if (!RefactoringUtil.isLoopOrIf(anchorElementHere.getParent())) {
|
||||
anchorElementHere.getParent().addBefore(assignStatement, getNormalizedAnchor(anchorElementHere));
|
||||
}
|
||||
}
|
||||
@@ -821,8 +821,8 @@ public abstract class BaseExpressionToFieldHandler extends IntroduceHandlerBase
|
||||
}
|
||||
}
|
||||
|
||||
if (anchorElementHere != null && IntroduceVariableBase.isLoopOrIf(anchorElementHere.getParent())) {
|
||||
IntroduceVariableBase.putStatementInLoopBody(assignStatement, anchorElementHere.getParent(), anchorElementHere);
|
||||
if (anchorElementHere != null && RefactoringUtil.isLoopOrIf(anchorElementHere.getParent())) {
|
||||
RefactoringUtil.putStatementInLoopBody(assignStatement, anchorElementHere.getParent(), anchorElementHere);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -525,7 +525,7 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
|
||||
|
||||
final PsiElement tempContainer = anchorStatement.getParent();
|
||||
|
||||
if (!(tempContainer instanceof PsiCodeBlock) && !isLoopOrIf(tempContainer) && (tempContainer.getParent() instanceof PsiLambdaExpression)) {
|
||||
if (!(tempContainer instanceof PsiCodeBlock) && !RefactoringUtil.isLoopOrIf(tempContainer) && (tempContainer.getParent() instanceof PsiLambdaExpression)) {
|
||||
String message = RefactoringBundle.message("refactoring.is.not.supported.in.the.current.context", REFACTORING_NAME);
|
||||
showErrorMessage(project, editor, message);
|
||||
return false;
|
||||
@@ -714,7 +714,7 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
|
||||
final PsiElement container = tempContainer;
|
||||
|
||||
PsiElement child = anchorStatement;
|
||||
if (!isLoopOrIf(container)) {
|
||||
if (!RefactoringUtil.isLoopOrIf(container)) {
|
||||
child = locateAnchor(child);
|
||||
if (isFinalVariableOnLHS(expr)) {
|
||||
child = child.getNextSibling();
|
||||
@@ -724,7 +724,7 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
|
||||
|
||||
boolean tempDeleteSelf = false;
|
||||
final boolean replaceSelf = settings.isReplaceLValues() || !RefactoringUtil.isAssignmentLHS(expr);
|
||||
if (!isLoopOrIf(container)) {
|
||||
if (!RefactoringUtil.isLoopOrIf(container)) {
|
||||
if (expr.getParent() instanceof PsiExpressionStatement && anchor.equals(anchorStatement)) {
|
||||
PsiStatement statement = (PsiStatement) expr.getParent();
|
||||
PsiElement parent = statement.getParent();
|
||||
@@ -755,7 +755,7 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
|
||||
public void run() {
|
||||
try {
|
||||
PsiStatement statement = null;
|
||||
final boolean isInsideLoop = isLoopOrIf(container);
|
||||
final boolean isInsideLoop = RefactoringUtil.isLoopOrIf(container);
|
||||
if (!isInsideLoop && deleteSelf) {
|
||||
statement = (PsiStatement) expr.getParent();
|
||||
}
|
||||
@@ -823,7 +823,7 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
|
||||
}
|
||||
}
|
||||
|
||||
declaration = (PsiDeclarationStatement) putStatementInLoopBody(declaration, container, finalAnchorStatement);
|
||||
declaration = (PsiDeclarationStatement) RefactoringUtil.putStatementInLoopBody(declaration, container, finalAnchorStatement);
|
||||
declaration = (PsiDeclarationStatement)JavaCodeStyleManager.getInstance(project).shortenClassReferences(declaration);
|
||||
PsiVariable var = (PsiVariable) declaration.getDeclaredElements()[0];
|
||||
PsiUtil.setModifierProperty(var, PsiModifier.FINAL, settings.isDeclareFinal());
|
||||
@@ -912,60 +912,6 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
|
||||
return JavaPsiFacade.getInstance(project).getElementFactory().createExpressionFromText(text, parent);
|
||||
}
|
||||
|
||||
public static PsiStatement putStatementInLoopBody(PsiStatement declaration, PsiElement container, PsiElement finalAnchorStatement)
|
||||
throws IncorrectOperationException {
|
||||
final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(container.getProject()).getElementFactory();
|
||||
if(isLoopOrIf(container)) {
|
||||
PsiStatement loopBody = getLoopBody(container, finalAnchorStatement);
|
||||
PsiStatement loopBodyCopy = loopBody != null ? (PsiStatement) loopBody.copy() : null;
|
||||
PsiBlockStatement blockStatement = (PsiBlockStatement)elementFactory
|
||||
.createStatementFromText("{}", null);
|
||||
blockStatement = (PsiBlockStatement) CodeStyleManager.getInstance(container.getProject()).reformat(blockStatement);
|
||||
final PsiElement prevSibling = loopBody.getPrevSibling();
|
||||
if(prevSibling instanceof PsiWhiteSpace) {
|
||||
final PsiElement pprev = prevSibling.getPrevSibling();
|
||||
if (!(pprev instanceof PsiComment) || !((PsiComment)pprev).getTokenType().equals(JavaTokenType.END_OF_LINE_COMMENT)) {
|
||||
prevSibling.delete();
|
||||
}
|
||||
}
|
||||
blockStatement = (PsiBlockStatement) loopBody.replace(blockStatement);
|
||||
final PsiCodeBlock codeBlock = blockStatement.getCodeBlock();
|
||||
declaration = (PsiStatement) codeBlock.add(declaration);
|
||||
JavaCodeStyleManager.getInstance(declaration.getProject()).shortenClassReferences(declaration);
|
||||
if (loopBodyCopy != null) codeBlock.add(loopBodyCopy);
|
||||
} else if (container instanceof PsiLambdaExpression) {
|
||||
final PsiLambdaExpression lambdaExpression = (PsiLambdaExpression)container;
|
||||
final PsiElement lambdaExpressionBody = lambdaExpression.getBody();
|
||||
LOG.assertTrue(lambdaExpressionBody != null);
|
||||
|
||||
final PsiLambdaExpression expressionFromText = (PsiLambdaExpression)elementFactory
|
||||
.createExpressionFromText(lambdaExpression.getParameterList().getText() + " -> {}", lambdaExpression);
|
||||
PsiCodeBlock newBody = (PsiCodeBlock)expressionFromText.getBody();
|
||||
LOG.assertTrue(newBody != null);
|
||||
newBody.add(declaration);
|
||||
|
||||
final PsiStatement lastBodyStatement;
|
||||
if (LambdaUtil.getFunctionalInterfaceReturnType(lambdaExpression) == PsiType.VOID) {
|
||||
lastBodyStatement = elementFactory.createStatementFromText("a;", lambdaExpression);
|
||||
((PsiExpressionStatement)lastBodyStatement).getExpression().replace(lambdaExpressionBody);
|
||||
}
|
||||
else {
|
||||
lastBodyStatement = elementFactory.createStatementFromText("return a;", lambdaExpression);
|
||||
final PsiExpression returnValue = ((PsiReturnStatement)lastBodyStatement).getReturnValue();
|
||||
LOG.assertTrue(returnValue != null);
|
||||
returnValue.replace(lambdaExpressionBody);
|
||||
}
|
||||
newBody.add(lastBodyStatement);
|
||||
|
||||
final PsiLambdaExpression copy = (PsiLambdaExpression)lambdaExpression.replace(expressionFromText);
|
||||
newBody = (PsiCodeBlock)copy.getBody();
|
||||
LOG.assertTrue(newBody != null);
|
||||
declaration = newBody.getStatements()[0];
|
||||
declaration = (PsiStatement)JavaCodeStyleManager.getInstance(declaration.getProject()).shortenClassReferences(declaration);
|
||||
}
|
||||
return declaration;
|
||||
}
|
||||
|
||||
private boolean parentStatementNotFound(final Project project, Editor editor) {
|
||||
String message = RefactoringBundle.message("refactoring.is.not.supported.in.the.current.context", REFACTORING_NAME);
|
||||
showErrorMessage(project, editor, message);
|
||||
@@ -1002,30 +948,6 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
|
||||
|
||||
protected abstract void showErrorMessage(Project project, Editor editor, String message);
|
||||
|
||||
@Nullable
|
||||
private static PsiStatement getLoopBody(PsiElement container, PsiElement anchorStatement) {
|
||||
if(container instanceof PsiLoopStatement) {
|
||||
return ((PsiLoopStatement) container).getBody();
|
||||
}
|
||||
else if (container instanceof PsiIfStatement) {
|
||||
final PsiStatement thenBranch = ((PsiIfStatement)container).getThenBranch();
|
||||
if (thenBranch != null && PsiTreeUtil.isAncestor(thenBranch, anchorStatement, false)) {
|
||||
return thenBranch;
|
||||
}
|
||||
final PsiStatement elseBranch = ((PsiIfStatement)container).getElseBranch();
|
||||
if (elseBranch != null && PsiTreeUtil.isAncestor(elseBranch, anchorStatement, false)) {
|
||||
return elseBranch;
|
||||
}
|
||||
LOG.assertTrue(false);
|
||||
}
|
||||
LOG.assertTrue(false);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public static boolean isLoopOrIf(PsiElement element) {
|
||||
return element instanceof PsiLoopStatement || element instanceof PsiIfStatement;
|
||||
}
|
||||
|
||||
protected boolean reportConflicts(MultiMap<PsiElement,String> conflicts, Project project, IntroduceVariableSettings settings){
|
||||
return false;
|
||||
|
||||
@@ -965,6 +965,84 @@ public class RefactoringUtil {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static PsiStatement putStatementInLoopBody(PsiStatement declaration, PsiElement container, PsiElement finalAnchorStatement)
|
||||
throws IncorrectOperationException {
|
||||
final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(container.getProject()).getElementFactory();
|
||||
if(isLoopOrIf(container)) {
|
||||
PsiStatement loopBody = getLoopBody(container, finalAnchorStatement);
|
||||
PsiStatement loopBodyCopy = loopBody != null ? (PsiStatement) loopBody.copy() : null;
|
||||
PsiBlockStatement blockStatement = (PsiBlockStatement)elementFactory
|
||||
.createStatementFromText("{}", null);
|
||||
blockStatement = (PsiBlockStatement) CodeStyleManager.getInstance(container.getProject()).reformat(blockStatement);
|
||||
final PsiElement prevSibling = loopBody.getPrevSibling();
|
||||
if(prevSibling instanceof PsiWhiteSpace) {
|
||||
final PsiElement pprev = prevSibling.getPrevSibling();
|
||||
if (!(pprev instanceof PsiComment) || !((PsiComment)pprev).getTokenType().equals(JavaTokenType.END_OF_LINE_COMMENT)) {
|
||||
prevSibling.delete();
|
||||
}
|
||||
}
|
||||
blockStatement = (PsiBlockStatement) loopBody.replace(blockStatement);
|
||||
final PsiCodeBlock codeBlock = blockStatement.getCodeBlock();
|
||||
declaration = (PsiStatement) codeBlock.add(declaration);
|
||||
JavaCodeStyleManager.getInstance(declaration.getProject()).shortenClassReferences(declaration);
|
||||
if (loopBodyCopy != null) codeBlock.add(loopBodyCopy);
|
||||
} else if (container instanceof PsiLambdaExpression) {
|
||||
final PsiLambdaExpression lambdaExpression = (PsiLambdaExpression)container;
|
||||
final PsiElement lambdaExpressionBody = lambdaExpression.getBody();
|
||||
LOG.assertTrue(lambdaExpressionBody != null);
|
||||
|
||||
final PsiLambdaExpression expressionFromText = (PsiLambdaExpression)elementFactory
|
||||
.createExpressionFromText(lambdaExpression.getParameterList().getText() + " -> {}", lambdaExpression);
|
||||
PsiCodeBlock newBody = (PsiCodeBlock)expressionFromText.getBody();
|
||||
LOG.assertTrue(newBody != null);
|
||||
newBody.add(declaration);
|
||||
|
||||
final PsiStatement lastBodyStatement;
|
||||
if (LambdaUtil.getFunctionalInterfaceReturnType(lambdaExpression) == PsiType.VOID) {
|
||||
lastBodyStatement = elementFactory.createStatementFromText("a;", lambdaExpression);
|
||||
((PsiExpressionStatement)lastBodyStatement).getExpression().replace(lambdaExpressionBody);
|
||||
}
|
||||
else {
|
||||
lastBodyStatement = elementFactory.createStatementFromText("return a;", lambdaExpression);
|
||||
final PsiExpression returnValue = ((PsiReturnStatement)lastBodyStatement).getReturnValue();
|
||||
LOG.assertTrue(returnValue != null);
|
||||
returnValue.replace(lambdaExpressionBody);
|
||||
}
|
||||
newBody.add(lastBodyStatement);
|
||||
|
||||
final PsiLambdaExpression copy = (PsiLambdaExpression)lambdaExpression.replace(expressionFromText);
|
||||
newBody = (PsiCodeBlock)copy.getBody();
|
||||
LOG.assertTrue(newBody != null);
|
||||
declaration = newBody.getStatements()[0];
|
||||
declaration = (PsiStatement)JavaCodeStyleManager.getInstance(declaration.getProject()).shortenClassReferences(declaration);
|
||||
}
|
||||
return declaration;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiStatement getLoopBody(PsiElement container, PsiElement anchorStatement) {
|
||||
if(container instanceof PsiLoopStatement) {
|
||||
return ((PsiLoopStatement) container).getBody();
|
||||
}
|
||||
else if (container instanceof PsiIfStatement) {
|
||||
final PsiStatement thenBranch = ((PsiIfStatement)container).getThenBranch();
|
||||
if (thenBranch != null && PsiTreeUtil.isAncestor(thenBranch, anchorStatement, false)) {
|
||||
return thenBranch;
|
||||
}
|
||||
final PsiStatement elseBranch = ((PsiIfStatement)container).getElseBranch();
|
||||
if (elseBranch != null && PsiTreeUtil.isAncestor(elseBranch, anchorStatement, false)) {
|
||||
return elseBranch;
|
||||
}
|
||||
LOG.assertTrue(false);
|
||||
}
|
||||
LOG.assertTrue(false);
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean isLoopOrIf(PsiElement element) {
|
||||
return element instanceof PsiLoopStatement || element instanceof PsiIfStatement;
|
||||
}
|
||||
|
||||
public interface ImplicitConstructorUsageVisitor {
|
||||
void visitConstructor(PsiMethod constructor, PsiMethod baseConstructor);
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
class Test {
|
||||
void foo(String[] args){
|
||||
for (String aArg : args) {
|
||||
<selection>boolean a = aArg == null;
|
||||
if (aArg == null) continue;</selection>
|
||||
|
||||
System.out.println(aArg + a);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
class Test {
|
||||
void foo(String[] args){
|
||||
for (String aArg : args) {
|
||||
Inner inner = new Inner(aArg).invoke();
|
||||
if (inner.is()) continue;
|
||||
boolean a = inner.isA();
|
||||
|
||||
System.out.println(aArg + a);
|
||||
}
|
||||
}
|
||||
|
||||
private class Inner {
|
||||
private boolean myResult;
|
||||
private String aArg;
|
||||
private boolean a;
|
||||
|
||||
public Inner(String aArg) {
|
||||
this.aArg = aArg;
|
||||
}
|
||||
|
||||
boolean is() {
|
||||
return myResult;
|
||||
}
|
||||
|
||||
public boolean isA() {
|
||||
return a;
|
||||
}
|
||||
|
||||
public Inner invoke() {
|
||||
a = aArg == null;
|
||||
if (aArg == null) {
|
||||
myResult = true;
|
||||
return this;
|
||||
}
|
||||
myResult = false;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -110,4 +110,8 @@ public class ExtractMethodObjectWithMultipleExitPointsTest extends LightRefactor
|
||||
public void testExtractFromIfStatementInsideAnonymous() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testConditionalExitWithoutCodeBlock() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user