From b2cf7e2e4ba97483ed8ff3c8145da778a04a361a Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Fri, 22 Dec 2023 16:42:52 +0100 Subject: [PATCH] Java: Introduce field - disallow field with local class types that do not compile (IDEA-198440) GitOrigin-RevId: 52e0dfc48276061214da0b2ad0ef68a512bdf2ee --- .../introduceField/IntroduceFieldHandler.java | 26 ++++++++++++++----- .../beforeRejectFieldFromLocal.java | 8 ++++++ .../IntroduceFieldInSameClassTest.java | 12 +++++++++ .../messages/JavaRefactoringBundle.properties | 1 + 4 files changed, 41 insertions(+), 6 deletions(-) create mode 100644 java/java-tests/testData/refactoring/introduceField/beforeRejectFieldFromLocal.java diff --git a/java/java-impl-refactorings/src/com/intellij/refactoring/introduceField/IntroduceFieldHandler.java b/java/java-impl-refactorings/src/com/intellij/refactoring/introduceField/IntroduceFieldHandler.java index f9fe03e3f2d8..59a17349dd5a 100644 --- a/java/java-impl-refactorings/src/com/intellij/refactoring/introduceField/IntroduceFieldHandler.java +++ b/java/java-impl-refactorings/src/com/intellij/refactoring/introduceField/IntroduceFieldHandler.java @@ -7,6 +7,7 @@ import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.NlsContexts; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.WindowManager; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; @@ -17,6 +18,7 @@ import com.intellij.refactoring.introduce.inplace.AbstractInplaceIntroducer; import com.intellij.refactoring.AbstractJavaInplaceIntroducer; import com.intellij.refactoring.ui.TypeSelectorManagerImpl; import com.intellij.refactoring.util.CommonRefactoringUtil; +import com.intellij.refactoring.util.RefactoringUIUtil; import com.intellij.refactoring.util.occurrences.*; import com.intellij.util.JavaPsiConstructorUtil; import org.jetbrains.annotations.NotNull; @@ -38,13 +40,26 @@ public class IntroduceFieldHandler extends BaseExpressionToFieldHandler implemen @Override protected boolean validClass(PsiClass parentClass, PsiExpression selectedExpr, Editor editor) { if (parentClass.isInterface()) { - String message = RefactoringBundle.getCannotRefactorMessage(JavaRefactoringBundle.message("cannot.introduce.field.in.interface")); - CommonRefactoringUtil.showErrorHint(parentClass.getProject(), editor, message, getRefactoringNameText(), getHelpID()); + String message = JavaRefactoringBundle.message("cannot.introduce.field.in.interface"); + showErrorMessage(parentClass.getProject(), editor, message); + return false; + } + PsiClass aClass = PsiUtil.resolveClassInClassTypeOnly(selectedExpr.getType()); + if (aClass != null && PsiUtil.isLocalClass(aClass) && !PsiTreeUtil.isAncestor(aClass, parentClass, false)) { + String message = JavaRefactoringBundle.message("0.is.not.visible.to.members.of.1", + RefactoringUIUtil.getDescription(aClass, false), + RefactoringUIUtil.getDescription(parentClass, false)); + showErrorMessage(aClass.getProject(), editor, StringUtil.capitalize(message)); return false; } return true; } + private void showErrorMessage(@NotNull Project project, Editor editor, @NlsContexts.DialogMessage String message) { + message = RefactoringBundle.getCannotRefactorMessage(message); + CommonRefactoringUtil.showErrorHint(project, editor, message, getRefactoringNameText(), getHelpID()); + } + @Override protected String getHelpID() { return HelpID.INTRODUCE_FIELD; @@ -177,18 +192,17 @@ public class IntroduceFieldHandler extends BaseExpressionToFieldHandler implemen protected boolean invokeImpl(final Project project, PsiLocalVariable localVariable, final Editor editor) { final PsiElement parent = localVariable.getParent(); if (!(parent instanceof PsiDeclarationStatement)) { - String message = RefactoringBundle.getCannotRefactorMessage(JavaRefactoringBundle.message("error.wrong.caret.position.local.or.expression.name")); - CommonRefactoringUtil.showErrorHint(project, editor, message, getRefactoringNameText(), getHelpID()); + showErrorMessage(project, editor, JavaRefactoringBundle.message("error.wrong.caret.position.local.or.expression.name")); return false; } LocalToFieldHandler localToFieldHandler = new LocalToFieldHandler(project, false){ @Override protected Settings showRefactoringDialog(PsiClass aClass, PsiLocalVariable local, - PsiExpression[] occurences, + PsiExpression[] occurrences, boolean isStatic) { final PsiStatement statement = PsiTreeUtil.getParentOfType(local, PsiStatement.class); - return IntroduceFieldHandler.this.showRefactoringDialog(project, editor, aClass, local.getInitializer(), local.getType(), occurences, local, statement); + return IntroduceFieldHandler.this.showRefactoringDialog(project, editor, aClass, local.getInitializer(), local.getType(), occurrences, local, statement); } @Override diff --git a/java/java-tests/testData/refactoring/introduceField/beforeRejectFieldFromLocal.java b/java/java-tests/testData/refactoring/introduceField/beforeRejectFieldFromLocal.java new file mode 100644 index 000000000000..9728eb13e482 --- /dev/null +++ b/java/java-tests/testData/refactoring/introduceField/beforeRejectFieldFromLocal.java @@ -0,0 +1,8 @@ +class K { + void m() { + class Local { + void locally() {} + } + new Local().locally(); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/refactoring/IntroduceFieldInSameClassTest.java b/java/java-tests/testSrc/com/intellij/java/refactoring/IntroduceFieldInSameClassTest.java index 6755acdc3c48..4b131c2e66f1 100644 --- a/java/java-tests/testSrc/com/intellij/java/refactoring/IntroduceFieldInSameClassTest.java +++ b/java/java-tests/testSrc/com/intellij/java/refactoring/IntroduceFieldInSameClassTest.java @@ -116,6 +116,18 @@ public class IntroduceFieldInSameClassTest extends LightJavaCodeInsightTestCase } } + public void testRejectFieldFromLocal() { + configureByFile("beforeRejectFieldFromLocal.java"); + try { + performRefactoring(BaseExpressionToFieldHandler.InitializationPlace.IN_FIELD_DECLARATION, false); + fail("Should not proceed"); + } + catch (CommonRefactoringUtil.RefactoringErrorHintException e) { + assertEquals("Cannot perform refactoring.\n" + + "Local class Local is not visible to members of class K", e.getMessage()); + } + } + public void testStaticFieldInRecord() { doTest(BaseExpressionToFieldHandler.InitializationPlace.IN_FIELD_DECLARATION, true); } diff --git a/java/openapi/resources/messages/JavaRefactoringBundle.properties b/java/openapi/resources/messages/JavaRefactoringBundle.properties index 33cdba7a5482..678610008d3b 100644 --- a/java/openapi/resources/messages/JavaRefactoringBundle.properties +++ b/java/openapi/resources/messages/JavaRefactoringBundle.properties @@ -60,6 +60,7 @@ boolean.method.result=boolean method result can.t.restore.context.for.method.extraction=Can't restore context for method extraction cannot.find.or.create.destination.directory=Cannot find or create destination directory cannot.introduce.field.in.interface=Non-constant fields are not allowed in an interface. +0.is.not.visible.to.members.of.1={0} is not visible to members of {1} cannot.move=Cannot Move cannot.move.inner.class.0.into.itself=Cannot move inner class {0} into itself cannot.move.package.into.itself=Cannot move package into itself