Introduce variable: support extraction form switch labels (IDEA-128795)

This commit is contained in:
Tagir Valeev
2018-10-29 15:19:28 +07:00
parent fe02a931e9
commit cae1bccdf5
9 changed files with 91 additions and 7 deletions
@@ -589,6 +589,12 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
}
}
String enumInSwitchError = RefactoringUtil.checkEnumConstantInSwitchLabel(expr);
if (enumInSwitchError != null) {
showErrorMessage(project, editor, enumInSwitchError);
return false;
}
final PsiType originalType = RefactoringUtil.getTypeByExpressionWithExpectedType(expr);
if (originalType == null || LambdaUtil.notInferredType(originalType)) {
@@ -662,7 +668,7 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
getSettings(project, editor, expr, occurrences, typeSelectorManager, inFinalContext, hasWriteAccess, validator, chosenAnchor,
choice);
final boolean cantChangeFinalModifier = (hasWriteAccess || inFinalContext) && allChoice;
final boolean cantChangeFinalModifier = (hasWriteAccess && allChoice) || inFinalContext;
PsiExpression[] allOccurrences = Arrays.stream(occurrences)
.filter(occurrence -> allChoice || (noWriteChoice && !PsiUtil.isAccessedForWriting(occurrence)) || expr.equals(occurrence))
@@ -254,6 +254,12 @@ class VariableExtractor {
return firstOccurrence;
}
}
if (anchor instanceof PsiSwitchLabelStatement) {
PsiSwitchStatement statement = ((PsiSwitchLabelStatement)anchor).getEnclosingSwitchStatement();
if (statement != null) {
return statement;
}
}
if (RefactoringUtil.isLoopOrIf(anchor.getParent())) return anchor;
PsiElement child = locateAnchor(anchor);
if (IntroduceVariableBase.isFinalVariableOnLHS(expr)) {
@@ -46,9 +46,11 @@ import com.intellij.psi.search.SearchScope;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.*;
import com.intellij.refactoring.PackageWrapper;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.introduceField.ElementToWorkOn;
import com.intellij.refactoring.introduceVariable.IntroduceVariableBase;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.ObjectUtils;
import com.intellij.util.text.UniqueNameGenerator;
import gnu.trove.THashMap;
import org.jetbrains.annotations.Contract;
@@ -1024,6 +1026,16 @@ public class RefactoringUtil {
return EnsureCodeBlockImpl.ensureCodeBlock(expression);
}
public static String checkEnumConstantInSwitchLabel(PsiExpression expr) {
if (PsiUtil.skipParenthesizedExprUp(expr.getParent()) instanceof PsiSwitchLabelStatement) {
PsiReferenceExpression ref = ObjectUtils.tryCast(PsiUtil.skipParenthesizedExprDown(expr), PsiReferenceExpression.class);
if (ref != null && ref.resolve() instanceof PsiEnumConstant) {
return RefactoringBundle.getCannotRefactorMessage(RefactoringBundle.message("refactoring.introduce.variable.enum.in.label.message"));
}
}
return null;
}
public interface ImplicitConstructorUsageVisitor {
void visitConstructor(PsiMethod constructor, PsiMethod baseConstructor);
@@ -15,9 +15,7 @@
*/
package com.intellij.refactoring.util.occurrences;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiExpression;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.refactoring.introduceField.ElementToWorkOn;
import com.intellij.refactoring.util.RefactoringUtil;
@@ -87,11 +85,15 @@ public abstract class BaseOccurrenceManager implements OccurrenceManager {
PsiElement scopeToDeclare = null;
for (PsiExpression occurrence : occurrences) {
final PsiElement data = occurrence.getUserData(ElementToWorkOn.PARENT);
PsiElement element = data != null ? data : occurrence;
if (scopeToDeclare == null) {
scopeToDeclare = data != null ? data : occurrence;
scopeToDeclare = element;
}
else {
scopeToDeclare = PsiTreeUtil.findCommonParent(scopeToDeclare, data != null ? data : occurrence);
scopeToDeclare = PsiTreeUtil.findCommonParent(scopeToDeclare, element);
}
if (PsiTreeUtil.getParentOfType(element, PsiSwitchLabelStatement.class, true, PsiStatement.class) != null) {
return true;
}
}
if(scopeToDeclare == null) {
@@ -0,0 +1,14 @@
class A {
private void A() {
final int temp = 2;
switch (1) {
case 1:
System.out.println(1);
break;
case temp:
System.out.println(temp);
break;
}
}
}
@@ -0,0 +1,13 @@
class A {
private void A() {
switch (1) {
case 1:
System.out.println(1);
break;
case <selection>2</selection>:
System.out.println(2);
break;
}
}
}
@@ -0,0 +1,14 @@
class A {
private void A(X x) {
switch (x) {
case A:
System.out.println(1);
break;
case <selection>B</selection>:
System.out.println(2);
break;
}
}
}
enum X {A,B,C}
@@ -204,6 +204,21 @@ public class IntroduceVariableTest extends LightCodeInsightTestCase {
doTest(new MockIntroduceVariableHandler("temp", true, false, false, "Node"));
}
public void testCaseLabel() {
doTest(new MockIntroduceVariableHandler("temp", true, false, false, "int"));
}
public void testCaseLabelEnum() {
try {
doTest(new MockIntroduceVariableHandler("temp", true, false, false, ""));
}
catch (RuntimeException e) {
assertEquals("Error message:Cannot perform refactoring.\nEnum constant in switch label cannot be extracted", e.getMessage());
return;
}
fail("Should not be able to perform refactoring");
}
public void testIfConditionAndChain() {
doTest(new MockIntroduceVariableHandler("temp", true, false, false, CommonClassNames.JAVA_LANG_STRING));
}
@@ -846,4 +846,6 @@ generate.module.descriptors.build.required.message=Couldn't generate module desc
generate.module.descriptors.scanning.message=Scanning Compiler Output
generate.module.descriptors.collecting.message=Collecting Dependencies
generate.module.descriptors.analysing.message=Analysing Dependencies
generate.module.descriptors.preparing.message=Preparing Code
generate.module.descriptors.preparing.message=Preparing Code
refactoring.introduce.variable.enum.in.label.message=Enum constant in switch label cannot be extracted