Java: allow to "Inline to Anonymous Class" classes with static members (IDEA-360451)

GitOrigin-RevId: 835f91a1d35db9b78041da36c3bd147fa4e52ba3
This commit is contained in:
Bas Leijdekkers
2024-10-09 18:12:26 +02:00
committed by intellij-monorepo-bot
parent 06a7650ea2
commit 481fab7d13
4 changed files with 64 additions and 13 deletions

View File

@@ -12,6 +12,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.patterns.ElementPattern;
import com.intellij.patterns.PlatformPatterns;
import com.intellij.pom.java.JavaFeature;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.ClassInheritorsSearch;
@@ -108,8 +109,7 @@ public final class InlineToAnonymousClassHandler extends JavaInlineActionHandler
if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(
() -> ApplicationManager.getApplication().runReadAction(
() -> errorMessage.set(getCannotInlineMessage((PsiClass)psiClass.getNavigationElement()))),
JavaRefactoringBundle.message(
"inline.conflicts.progress"), true, project)) return;
JavaRefactoringBundle.message("inline.conflicts.progress"), true, project)) return;
if (errorMessage.get() != null) {
CommonRefactoringUtil.showErrorHint(project, editor, errorMessage.get(), JavaRefactoringBundle.message("inline.to.anonymous.refactoring"), null);
return;
@@ -203,7 +203,7 @@ public final class InlineToAnonymousClassHandler extends JavaInlineActionHandler
}
PsiClassType[] classTypes = psiClass.getExtendsListTypes();
for(PsiClassType classType: classTypes) {
for (PsiClassType classType: classTypes) {
PsiClass superClass = classType.resolve();
if (superClass == null) {
return JavaBundle.message("class.cannot.be.inlined.because.its.superclass.cannot.be.resolved");
@@ -229,7 +229,7 @@ public final class InlineToAnonymousClassHandler extends JavaInlineActionHandler
final GlobalSearchScope searchScope = GlobalSearchScope.projectScope(psiClass.getProject());
final PsiMethod[] methods = psiClass.getMethods();
for(PsiMethod method: methods) {
for (PsiMethod method: methods) {
if (method.isConstructor()) {
if (PsiUtil.findReturnStatements(method).length > 0) {
return JavaBundle.message("class.cannot.be.inlined.because.its.constructor.contains.return.statements");
@@ -241,15 +241,16 @@ public final class InlineToAnonymousClassHandler extends JavaInlineActionHandler
.message("class.cannot.be.inlined.because.there.are.usages.of.its.methods.not.inherited.from.its.superclass.or.interface");
}
}
if (method.hasModifierProperty(PsiModifier.STATIC)) {
if (method.hasModifierProperty(PsiModifier.STATIC) && !PsiUtil.isAvailable(JavaFeature.INNER_STATICS, method)) {
return JavaBundle.message("class.cannot.be.inlined.because.it.has.static.methods");
}
}
final PsiClass[] innerClasses = psiClass.getInnerClasses();
for(PsiClass innerClass: innerClasses) {
for (PsiClass innerClass: innerClasses) {
PsiModifierList classModifiers = innerClass.getModifierList();
if (classModifiers != null && classModifiers.hasModifierProperty(PsiModifier.STATIC)) {
if (classModifiers != null && classModifiers.hasModifierProperty(PsiModifier.STATIC) &&
!PsiUtil.isAvailable(JavaFeature.INNER_STATICS, innerClass)) {
return JavaBundle.message("class.cannot.be.inlined.because.it.has.static.inner.classes");
}
if (!ReferencesSearch.search(innerClass, searchScope).forEach(new AllowedUsagesProcessor(psiClass))) {
@@ -258,9 +259,10 @@ public final class InlineToAnonymousClassHandler extends JavaInlineActionHandler
}
final PsiField[] fields = psiClass.getFields();
for(PsiField field: fields) {
for (PsiField field: fields) {
final PsiModifierList fieldModifiers = field.getModifierList();
if (fieldModifiers != null && fieldModifiers.hasModifierProperty(PsiModifier.STATIC)) {
if (fieldModifiers != null && fieldModifiers.hasModifierProperty(PsiModifier.STATIC) &&
!PsiUtil.isAvailable(JavaFeature.INNER_STATICS, field)) {
if (!fieldModifiers.hasModifierProperty(PsiModifier.FINAL)) {
return JavaBundle.message("class.cannot.be.inlined.because.it.has.static.non.final.fields");
}
@@ -279,9 +281,10 @@ public final class InlineToAnonymousClassHandler extends JavaInlineActionHandler
}
final PsiClassInitializer[] initializers = psiClass.getInitializers();
for(PsiClassInitializer initializer: initializers) {
for (PsiClassInitializer initializer: initializers) {
final PsiModifierList modifiers = initializer.getModifierList();
if (modifiers != null && modifiers.hasModifierProperty(PsiModifier.STATIC)) {
if (modifiers != null && modifiers.hasModifierProperty(PsiModifier.STATIC) &&
!PsiUtil.isAvailable(JavaFeature.INNER_STATICS, initializer)) {
return JavaBundle.message("class.cannot.be.inlined.because.it.has.static.initializers");
}
}
@@ -292,7 +295,7 @@ public final class InlineToAnonymousClassHandler extends JavaInlineActionHandler
static boolean isRedundantImplements(@NotNull final PsiClass superClass, final PsiClassType interfaceType) {
boolean redundantImplements = false;
PsiClassType[] superClassInterfaces = superClass.getImplementsListTypes();
for(PsiClassType superClassInterface: superClassInterfaces) {
for (PsiClassType superClassInterface: superClassInterfaces) {
if (superClassInterface.equals(interfaceType)) {
redundantImplements = true;
break;
@@ -304,7 +307,7 @@ public final class InlineToAnonymousClassHandler extends JavaInlineActionHandler
@Nullable
private static @Nls String getCannotInlineDueToUsagesMessage(final PsiClass aClass) {
boolean hasUsages = false;
for(PsiReference reference : ReferencesSearch.search(aClass, GlobalSearchScope.projectScope(aClass.getProject()))) {
for (PsiReference reference : ReferencesSearch.search(aClass, GlobalSearchScope.projectScope(aClass.getProject()))) {
final PsiElement element = reference.getElement();
if (!PsiTreeUtil.isAncestor(aClass, element, false)) {
hasUsages = true;

View File

@@ -0,0 +1,22 @@
class A {
private Object b = new Inner();
private class <caret>Inner {
static String A;
public String toString() {
return "A";
}
public static void staticMethod() {
A = "";
System.out.println(A);
}
static class InnerInner {}
static {
// static initializer
}
}
}

View File

@@ -0,0 +1,21 @@
class A {
private Object b = new Object() {
static String A;
public String toString() {
return "A";
}
public static void staticMethod() {
A = "";
System.out.println(A);
}
static class InnerInner {}
static {
// static initializer
}
};
}

View File

@@ -259,6 +259,11 @@ public class InlineToAnonymousClassTest extends LightRefactoringTestCase {
doTest(true, false);
}
public void testStaticMembers() {
setLanguageLevel(LanguageLevel.JDK_16);
doTest(false, false);
}
public void testSealedNoMembers() {
setLanguageLevel(LanguageLevel.JDK_17);
doTest(false, false);