diff --git a/java/java-impl-refactorings/src/com/intellij/refactoring/extractMethod/newImpl/ExtractOptionsPipeline.kt b/java/java-impl-refactorings/src/com/intellij/refactoring/extractMethod/newImpl/ExtractOptionsPipeline.kt index a35dc1c24838..145fd48b3c70 100644 --- a/java/java-impl-refactorings/src/com/intellij/refactoring/extractMethod/newImpl/ExtractOptionsPipeline.kt +++ b/java/java-impl-refactorings/src/com/intellij/refactoring/extractMethod/newImpl/ExtractOptionsPipeline.kt @@ -2,6 +2,7 @@ package com.intellij.refactoring.extractMethod.newImpl import com.intellij.codeInsight.AnnotationUtil.* +import com.intellij.codeInsight.daemon.impl.analysis.HighlightingFeature import com.intellij.codeInsight.daemon.impl.analysis.JavaHighlightUtil import com.intellij.codeInsight.daemon.impl.quickfix.AnonymousTargetClassPreselectionUtil import com.intellij.codeInsight.navigation.PsiTargetNavigator @@ -222,7 +223,8 @@ object ExtractMethodPipeline { fun withForcedStatic(analyzer: CodeFragmentAnalyzer, extractOptions: ExtractOptions): ExtractOptions? { val targetClass = PsiTreeUtil.getParentOfType(extractOptions.anchor, PsiClass::class.java)!! - if (PsiUtil.isLocalOrAnonymousClass(targetClass) || PsiUtil.isInnerClass(targetClass)) return null + val isInnerClass = PsiUtil.isLocalOrAnonymousClass(targetClass) || PsiUtil.isInnerClass(targetClass) + if (isInnerClass && !HighlightingFeature.INNER_STATICS.isAvailable(targetClass)) return null val memberUsages = analyzer.findInstanceMemberUsages(targetClass, extractOptions.elements) if (memberUsages.any(::isNotExtractableUsage)) return null val addedParameters = memberUsages.groupBy(MemberUsage::member).entries diff --git a/java/java-tests/testData/refactoring/extractMethodAndDuplicatesInplace/MakeStaticInsideInner.java b/java/java-tests/testData/refactoring/extractMethodAndDuplicatesInplace/MakeStaticInsideInner.java new file mode 100644 index 000000000000..39c55288103e --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethodAndDuplicatesInplace/MakeStaticInsideInner.java @@ -0,0 +1,8 @@ +class X { + Runnable r = new Runnable() { + @Override + public void run() { + System.out.println("hello"); + } + }; +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/extractMethodAndDuplicatesInplace/MakeStaticInsideInnerFail.java b/java/java-tests/testData/refactoring/extractMethodAndDuplicatesInplace/MakeStaticInsideInnerFail.java new file mode 100644 index 000000000000..39c55288103e --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethodAndDuplicatesInplace/MakeStaticInsideInnerFail.java @@ -0,0 +1,8 @@ +class X { + Runnable r = new Runnable() { + @Override + public void run() { + System.out.println("hello"); + } + }; +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/extractMethodAndDuplicatesInplace/MakeStaticInsideInnerFail_after.java b/java/java-tests/testData/refactoring/extractMethodAndDuplicatesInplace/MakeStaticInsideInnerFail_after.java new file mode 100644 index 000000000000..1bb43086c7ab --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethodAndDuplicatesInplace/MakeStaticInsideInnerFail_after.java @@ -0,0 +1,12 @@ +class X { + Runnable r = new Runnable() { + @Override + public void run() { + extracted(); + } + + private void extracted() { + System.out.println("hello"); + } + }; +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/extractMethodAndDuplicatesInplace/MakeStaticInsideInner_after.java b/java/java-tests/testData/refactoring/extractMethodAndDuplicatesInplace/MakeStaticInsideInner_after.java new file mode 100644 index 000000000000..2788dd08b79b --- /dev/null +++ b/java/java-tests/testData/refactoring/extractMethodAndDuplicatesInplace/MakeStaticInsideInner_after.java @@ -0,0 +1,12 @@ +class X { + Runnable r = new Runnable() { + @Override + public void run() { + extracted(); + } + + private static void extracted() { + System.out.println("hello"); + } + }; +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/refactoring/ExtractMethodAndDuplicatesInplaceTest.kt b/java/java-tests/testSrc/com/intellij/java/refactoring/ExtractMethodAndDuplicatesInplaceTest.kt index d55270aa0694..da8b8d8aa645 100644 --- a/java/java-tests/testSrc/com/intellij/java/refactoring/ExtractMethodAndDuplicatesInplaceTest.kt +++ b/java/java-tests/testSrc/com/intellij/java/refactoring/ExtractMethodAndDuplicatesInplaceTest.kt @@ -5,9 +5,12 @@ import com.intellij.codeInsight.lookup.LookupManager import com.intellij.codeInsight.template.impl.TemplateManagerImpl import com.intellij.codeInsight.template.impl.TemplateState import com.intellij.ide.DataManager +import com.intellij.ide.IdeEventQueue +import com.intellij.ide.IdePopupManager import com.intellij.openapi.actionSystem.* import com.intellij.openapi.command.WriteCommandAction import com.intellij.openapi.editor.Editor +import com.intellij.openapi.ui.popup.JBPopup import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.TextRange import com.intellij.pom.java.LanguageLevel @@ -20,6 +23,8 @@ import com.intellij.refactoring.listeners.RefactoringEventListener import com.intellij.refactoring.util.CommonRefactoringUtil.RefactoringErrorHintException import com.intellij.testFramework.IdeaTestUtil import com.intellij.testFramework.LightJavaCodeInsightTestCase +import com.intellij.ui.UiInterceptors +import com.intellij.ui.UiInterceptors.UiInterceptor import com.intellij.util.ui.UIUtil import org.jetbrains.annotations.NonNls @@ -326,9 +331,29 @@ class ExtractMethodAndDuplicatesInplaceTest: LightJavaCodeInsightTestCase() { } fun testIntroduceObjectInsideNestedClass(){ + IdeEventQueue.getInstance().popupManager.closeAllPopups() + IdePopupManager().closeAllPopups() doTest() } + fun testMakeStaticInsideInner(){ + UiInterceptors.register(DefaultChooserInterceptor) + doTest() + } + + fun testMakeStaticInsideInnerFail(){ + IdeaTestUtil.withLevel(module, LanguageLevel.JDK_15) { + UiInterceptors.register(DefaultChooserInterceptor) + doTest() + } + } + + object DefaultChooserInterceptor: UiInterceptor(JBPopup::class.java){ + override fun doIntercept(component: JBPopup) { + component.closeOk(null) + } + } + fun testMakeStaticFailsWithClassUsage(){ JavaRefactoringSettings.getInstance().EXTRACT_STATIC_METHOD_AND_PASS_FIELDS = true doTest() diff --git a/java/java-tests/testSrc/com/intellij/java/refactoring/ExtractMethodNewTest.java b/java/java-tests/testSrc/com/intellij/java/refactoring/ExtractMethodNewTest.java index 530fb28ae235..6f8e254a9ca6 100644 --- a/java/java-tests/testSrc/com/intellij/java/refactoring/ExtractMethodNewTest.java +++ b/java/java-tests/testSrc/com/intellij/java/refactoring/ExtractMethodNewTest.java @@ -26,6 +26,7 @@ import com.intellij.refactoring.extractMethod.PrepareFailedException; import com.intellij.refactoring.extractMethod.newImpl.ExtractException; import com.intellij.refactoring.extractMethod.newImpl.MethodExtractor; import com.intellij.refactoring.util.duplicates.Match; +import com.intellij.testFramework.IdeaTestUtil; import com.intellij.testFramework.LightJavaCodeInsightTestCase; import com.intellij.util.ArrayUtilRt; import com.intellij.util.IncorrectOperationException; @@ -1440,12 +1441,14 @@ public class ExtractMethodNewTest extends LightJavaCodeInsightTestCase { } public void testNoStaticForInnerClass() { - try { - configureByFile(BASE_PATH + getTestName(false) + ".java"); - performExtractMethod(true, true, getEditor(), getFile(), getProject(), false, null, true, null, null, null); - fail("Static modifier is forbidden inside inner classes"); - } catch (PrepareFailedException e){ - } + IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_15, () -> { + try { + configureByFile(BASE_PATH + getTestName(false) + ".java"); + performExtractMethod(true, true, getEditor(), getFile(), getProject(), false, null, true, null, null, null); + fail("Static modifier is forbidden inside inner classes"); + } catch (PrepareFailedException ignored){ + } + }); } public void testStaticForNestedClass() throws Exception {