diff --git a/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java b/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java index 43a88ff220c8..739e0682c837 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceVariable/IntroduceVariableBase.java @@ -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)) diff --git a/java/java-impl/src/com/intellij/refactoring/introduceVariable/VariableExtractor.java b/java/java-impl/src/com/intellij/refactoring/introduceVariable/VariableExtractor.java index 4f9a76a4fd88..d1e3ef068d41 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceVariable/VariableExtractor.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceVariable/VariableExtractor.java @@ -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)) { diff --git a/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java b/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java index 3c3dc8494461..27861da1d4ce 100644 --- a/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java +++ b/java/java-impl/src/com/intellij/refactoring/util/RefactoringUtil.java @@ -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); diff --git a/java/java-impl/src/com/intellij/refactoring/util/occurrences/BaseOccurrenceManager.java b/java/java-impl/src/com/intellij/refactoring/util/occurrences/BaseOccurrenceManager.java index 4c240c2decc9..797b5c39566f 100644 --- a/java/java-impl/src/com/intellij/refactoring/util/occurrences/BaseOccurrenceManager.java +++ b/java/java-impl/src/com/intellij/refactoring/util/occurrences/BaseOccurrenceManager.java @@ -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) { diff --git a/java/java-tests/testData/refactoring/introduceVariable/CaseLabel.after.java b/java/java-tests/testData/refactoring/introduceVariable/CaseLabel.after.java new file mode 100644 index 000000000000..8c05ab174f12 --- /dev/null +++ b/java/java-tests/testData/refactoring/introduceVariable/CaseLabel.after.java @@ -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; + } + + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/introduceVariable/CaseLabel.java b/java/java-tests/testData/refactoring/introduceVariable/CaseLabel.java new file mode 100644 index 000000000000..7cb66dd6028a --- /dev/null +++ b/java/java-tests/testData/refactoring/introduceVariable/CaseLabel.java @@ -0,0 +1,13 @@ +class A { + private void A() { + switch (1) { + case 1: + System.out.println(1); + break; + case 2: + System.out.println(2); + break; + } + + } +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/introduceVariable/CaseLabelEnum.java b/java/java-tests/testData/refactoring/introduceVariable/CaseLabelEnum.java new file mode 100644 index 000000000000..7ba1668188ce --- /dev/null +++ b/java/java-tests/testData/refactoring/introduceVariable/CaseLabelEnum.java @@ -0,0 +1,14 @@ +class A { + private void A(X x) { + switch (x) { + case A: + System.out.println(1); + break; + case B: + System.out.println(2); + break; + } + + } +} +enum X {A,B,C} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/refactoring/IntroduceVariableTest.java b/java/java-tests/testSrc/com/intellij/java/refactoring/IntroduceVariableTest.java index d01b2feb8fff..7e7c11d3c8e8 100644 --- a/java/java-tests/testSrc/com/intellij/java/refactoring/IntroduceVariableTest.java +++ b/java/java-tests/testSrc/com/intellij/java/refactoring/IntroduceVariableTest.java @@ -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)); } diff --git a/platform/platform-resources-en/src/messages/RefactoringBundle.properties b/platform/platform-resources-en/src/messages/RefactoringBundle.properties index bdf89ec77a2e..918d2ffb2d95 100644 --- a/platform/platform-resources-en/src/messages/RefactoringBundle.properties +++ b/platform/platform-resources-en/src/messages/RefactoringBundle.properties @@ -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 \ No newline at end of file +generate.module.descriptors.preparing.message=Preparing Code + +refactoring.introduce.variable.enum.in.label.message=Enum constant in switch label cannot be extracted \ No newline at end of file