extract method object: process exit statements as they may contain refs to outer vars (IDEA-96772); disable duplicate extraction

This commit is contained in:
anna
2012-12-06 17:51:47 +01:00
parent 55d264c176
commit fabf91af4d
5 changed files with 89 additions and 3 deletions

View File

@@ -130,7 +130,7 @@ public class ExtractMethodProcessor implements MatchProvider {
private List<Match> myDuplicates;
@PsiModifier.ModifierConstant private String myMethodVisibility = PsiModifier.PRIVATE;
protected boolean myGenerateConditionalExit;
private PsiStatement myFirstExitStatementCopy;
protected PsiStatement myFirstExitStatementCopy;
private PsiMethod myExtractedMethod;
private PsiMethodCallExpression myMethodCall;
private boolean myNullConditionalCheck = false;
@@ -725,7 +725,7 @@ public class ExtractMethodProcessor implements MatchProvider {
PsiIfStatement ifStatement = (PsiIfStatement)myElementFactory.createStatementFromText("if (a) b;", null);
ifStatement = (PsiIfStatement)addToMethodCallLocation(ifStatement);
myMethodCall = (PsiMethodCallExpression)ifStatement.getCondition().replace(myMethodCall);
ifStatement.getThenBranch().replace(myFirstExitStatementCopy);
myFirstExitStatementCopy = (PsiStatement)ifStatement.getThenBranch().replace(myFirstExitStatementCopy);
CodeStyleManager.getInstance(myProject).reformat(ifStatement);
}
else if (myOutputVariable != null) {

View File

@@ -266,7 +266,7 @@ public class ExtractMethodObjectProcessor extends BaseRefactoringProcessor {
}
final PsiCodeBlock body = getMethod().getBody();
LOG.assertTrue(body != null);
final List<PsiLocalVariable> vars = new ArrayList<PsiLocalVariable>();
final LinkedHashSet<PsiLocalVariable> vars = new LinkedHashSet<PsiLocalVariable>();
final Map<PsiElement, PsiElement> replacementMap = new LinkedHashMap<PsiElement, PsiElement>();
final List<PsiReturnStatement> returnStatements = new ArrayList<PsiReturnStatement>();
body.accept(new JavaRecursiveElementWalkingVisitor() {
@@ -787,12 +787,45 @@ public class ExtractMethodObjectProcessor extends BaseRefactoringProcessor {
} else if (myElements[0] instanceof PsiPostfixExpression || myElements[0] instanceof PsiPrefixExpression) {
getMethodCall().getParent().replace(((PsiBinaryExpression)getMethodCall().getParent()).getLOperand());
}
rebindExitStatement(object);
}
else {
super.declareNecessaryVariablesAfterCall(outputVariable);
}
}
private void rebindExitStatement(final String objectName) {
final PsiStatement exitStatementCopy = myExtractProcessor.myFirstExitStatementCopy;
if (exitStatementCopy != null) {
myExtractProcessor.getDuplicates().clear();
final Map<String, PsiVariable> outVarsNames = new HashMap<String, PsiVariable>();
for (PsiVariable variable : myOutputVariables) {
outVarsNames.put(variable.getName(), variable);
}
final Map<PsiElement, PsiElement> replaceMap = new HashMap<PsiElement, PsiElement>();
exitStatementCopy.accept(new JavaRecursiveElementWalkingVisitor() {
@Override
public void visitReferenceExpression(PsiReferenceExpression expression) {
super.visitReferenceExpression(expression);
if (expression.resolve() == null) {
final PsiVariable variable = outVarsNames.get(expression.getReferenceName());
if (variable != null) {
final String call2Getter = objectName + "." + PropertyUtil.suggestGetterName(getPureName(variable), variable.getType()) + "()";
final PsiExpression callToGetter = myElementFactory.createExpressionFromText(call2Getter, variable);
replaceMap.put(expression, callToGetter);
}
}
}
});
for (PsiElement element : replaceMap.keySet()) {
if (element.isValid()) {
element.replace(replaceMap.get(element));
}
}
}
}
public boolean generatesConditionalExit() {
return myGenerateConditionalExit;
}

View File

@@ -0,0 +1,14 @@
class A {
boolean foo() {
<selection>for (int i = 0; i < 9; i++) {
final Boolean foo = Boolean.FALSE;
if (foo != null) {
return foo;
}
}</selection>
return false;
}
}

View File

@@ -0,0 +1,35 @@
class A {
boolean foo() {
Inner inner = new Inner().invoke();
if (inner.is()) return inner.getFoo();
return false;
}
private class Inner {
private boolean myResult;
private Boolean foo;
boolean is() {
return myResult;
}
public Boolean getFoo() {
return foo;
}
public Inner invoke() {
for (int i = 0; i < 9; i++) {
foo = Boolean.FALSE;
if (foo != null) {
myResult = true;
return this;
}
}
myResult = false;
return this;
}
}
}

View File

@@ -114,4 +114,8 @@ public class ExtractMethodObjectWithMultipleExitPointsTest extends LightRefactor
public void testConditionalExitWithoutCodeBlock() throws Exception {
doTest();
}
public void testReturnExitStatement() throws Exception {
doTest();
}
}