mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Java: allow to introduce a constant as a field of an inner, local or anonymous class (IDEA-341923)
for Introduce Constant refactoring. Also fixes IDEABKL-3269 when introducing a compile-time constant from an expression. GitOrigin-RevId: 169e7ee8e14306a265948537b62746d9a26c0298
This commit is contained in:
committed by
intellij-monorepo-bot
parent
cf79dfa709
commit
0dbc31a8b6
+6
-8
@@ -295,14 +295,12 @@ public abstract class BaseExpressionToFieldHandler extends IntroduceHandlerBase
|
||||
}
|
||||
|
||||
public @Nullable PsiClass getParentClass(@NotNull PsiExpression initializerExpression) {
|
||||
PsiElement element = initializerExpression.getUserData(ElementToWorkOn.PARENT);
|
||||
if (element == null) element = initializerExpression.getParent();
|
||||
PsiElement parent = element;
|
||||
while (parent != null) {
|
||||
if (parent instanceof PsiClass && (!myIsConstant || LocalToFieldHandler.mayContainConstants((PsiClass)parent))) {
|
||||
return (PsiClass)parent;
|
||||
}
|
||||
parent = PsiTreeUtil.getParentOfType(parent, PsiClass.class);
|
||||
boolean compileTimeConstant = LocalToFieldHandler.isCompileTimeConstant(initializerExpression, initializerExpression.getType());
|
||||
PsiElement parent = initializerExpression.getUserData(ElementToWorkOn.PARENT);
|
||||
PsiClass aClass = PsiTreeUtil.getParentOfType((parent == null) ? initializerExpression : parent, PsiClass.class);
|
||||
while (aClass != null) {
|
||||
if (!myIsConstant || compileTimeConstant || LocalToFieldHandler.isStaticFieldAllowed(aClass)) return aClass;
|
||||
aClass = PsiTreeUtil.getParentOfType(aClass, PsiClass.class);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
+1
-21
@@ -16,7 +16,6 @@ import com.intellij.openapi.wm.WindowManager;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.refactoring.HelpID;
|
||||
import com.intellij.refactoring.JavaRefactoringSettings;
|
||||
import com.intellij.refactoring.PreviewableRefactoringActionHandler;
|
||||
@@ -208,7 +207,7 @@ public class IntroduceConstantHandler extends BaseExpressionToFieldHandler imple
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractInplaceIntroducer getInplaceIntroducer() {
|
||||
public InplaceIntroduceConstantPopup getInplaceIntroducer() {
|
||||
return myInplaceIntroduceConstantPopup;
|
||||
}
|
||||
|
||||
@@ -217,25 +216,6 @@ public class IntroduceConstantHandler extends BaseExpressionToFieldHandler imple
|
||||
return new ExpressionOccurrenceManager(selectedExpr, parentClass, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiClass getParentClass(@NotNull PsiExpression initializerExpression) {
|
||||
final PsiType type = initializerExpression.getType();
|
||||
|
||||
if (PsiUtil.isConstantExpression(initializerExpression) &&
|
||||
(type instanceof PsiPrimitiveType || type != null && type.equalsToText(CommonClassNames.JAVA_LANG_STRING))) {
|
||||
return super.getParentClass(initializerExpression);
|
||||
}
|
||||
|
||||
PsiElement parent = initializerExpression.getUserData(ElementToWorkOn.PARENT);
|
||||
if (parent == null) parent = initializerExpression;
|
||||
PsiClass aClass = PsiTreeUtil.getParentOfType(parent, PsiClass.class);
|
||||
while (aClass != null) {
|
||||
if (LocalToFieldHandler.mayContainConstants(aClass)) return aClass;
|
||||
aClass = PsiTreeUtil.getParentOfType(aClass, PsiClass.class);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean accept(ElementToWorkOn elementToWorkOn) {
|
||||
final PsiExpression expr = elementToWorkOn.getExpression();
|
||||
|
||||
+29
-6
@@ -4,6 +4,7 @@ package com.intellij.refactoring.introduceField;
|
||||
import com.intellij.codeInsight.ChangeContextUtil;
|
||||
import com.intellij.codeInsight.CodeInsightUtil;
|
||||
import com.intellij.codeInsight.TestFrameworks;
|
||||
import com.intellij.codeInsight.daemon.impl.analysis.HighlightingFeature;
|
||||
import com.intellij.codeInsight.daemon.impl.quickfix.AnonymousTargetClassPreselectionUtil;
|
||||
import com.intellij.codeInsight.generation.GenerateMembersUtil;
|
||||
import com.intellij.codeInsight.navigation.PsiTargetNavigator;
|
||||
@@ -32,6 +33,7 @@ import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.VisibilityUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@@ -55,12 +57,11 @@ public abstract class LocalToFieldHandler {
|
||||
|
||||
public boolean convertLocalToField(final PsiLocalVariable local, final Editor editor) {
|
||||
boolean tempIsStatic = myIsConstant;
|
||||
PsiElement parent = local.getParent();
|
||||
PsiType localType = local.getType();
|
||||
boolean runtimeConstant = (localType instanceof PsiPrimitiveType || localType.equalsToText(CommonClassNames.JAVA_LANG_STRING)) && PsiUtil.isConstantExpression(local.getInitializer());
|
||||
boolean compileTimeConstant = isCompileTimeConstant(local.getInitializer(), local.getType());
|
||||
final List<PsiClass> classes = new ArrayList<>();
|
||||
PsiElement parent = local.getParent();
|
||||
while (parent != null && parent.getContainingFile() != null) {
|
||||
if (parent instanceof PsiClass && (runtimeConstant || !myIsConstant || mayContainConstants((PsiClass) parent))) {
|
||||
if (parent instanceof PsiClass && (compileTimeConstant || !myIsConstant || isStaticFieldAllowed((PsiClass) parent))) {
|
||||
classes.add((PsiClass)parent);
|
||||
}
|
||||
if (parent instanceof PsiFile && FileTypeUtils.isInServerPageFile(parent)) {
|
||||
@@ -100,9 +101,31 @@ public abstract class LocalToFieldHandler {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean isCompileTimeConstant(@Nullable PsiExpression initializer, @Nullable PsiType type) {
|
||||
return type != null && (type instanceof PsiPrimitiveType || type.equalsToText(CommonClassNames.JAVA_LANG_STRING)) &&
|
||||
PsiUtil.isConstantExpression(initializer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #isStaticFieldAllowed(PsiClass)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public static boolean mayContainConstants(@NotNull PsiClass aClass) {
|
||||
return aClass.hasModifierProperty(PsiModifier.STATIC) ||
|
||||
aClass.getParent() instanceof PsiJavaFile;
|
||||
return isStaticFieldAllowed(aClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if adding a static field is allowed in the specified class.
|
||||
* Before Java 16 this was only allowed for inner, local and anonymous classes,
|
||||
* if the static field was a compile-time constant.
|
||||
* @param aClass the class to check
|
||||
* @return true, if adding a non-compile-time constants static field to the specified class is allowed. False otherwise.
|
||||
*/
|
||||
public static boolean isStaticFieldAllowed(@NotNull PsiClass aClass) {
|
||||
if (HighlightingFeature.INNER_STATICS.isAvailable(aClass)) {
|
||||
return true;
|
||||
}
|
||||
return aClass.hasModifierProperty(PsiModifier.STATIC) || aClass.getParent() instanceof PsiJavaFile;
|
||||
}
|
||||
|
||||
protected int getChosenClassIndex(List<PsiClass> classes) {
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
class Foo {
|
||||
class Bar {
|
||||
void foo() {
|
||||
String str = <caret>"42";
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
class Foo {
|
||||
class Bar {
|
||||
public static final String xxx = "42";
|
||||
|
||||
void foo() {
|
||||
String str = xxx;
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
-3
@@ -1,9 +1,11 @@
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
|
||||
class Foo {
|
||||
class Bar {
|
||||
public static final String xxx = "42";
|
||||
@NonNls
|
||||
private static final String xxx = "42";
|
||||
|
||||
void foo() {
|
||||
String str = xxx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
class X {
|
||||
|
||||
void x() {
|
||||
new Object() {
|
||||
void x() {
|
||||
System.out.println(<selection>new <caret>Object()</selection>);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
class X {
|
||||
|
||||
void x() {
|
||||
new Object() {
|
||||
void x() {
|
||||
System.out.println(<selection>new <caret>Object()</selection>);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
class X {
|
||||
|
||||
public static final Object xxx = new Object();
|
||||
|
||||
void x() {
|
||||
new Object() {
|
||||
void x() {
|
||||
System.out.println(xxx);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
class X {
|
||||
|
||||
void x() {
|
||||
new Object() {
|
||||
public static final Object xxx = new Object();
|
||||
|
||||
void x() {
|
||||
System.out.println(xxx);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,7 @@ public class IntroduceConstantTest extends LightJavaCodeInsightTestCase {
|
||||
public void testNonStaticContainerForCompileTimeConstant() {
|
||||
configureByFile(BASE_PATH + getTestName(false) + ".java");
|
||||
PsiLocalVariable local = PsiTreeUtil.getParentOfType(getFile().findElementAt(getEditor().getCaretModel().getOffset()), PsiLocalVariable.class);
|
||||
new MockLocalToFieldHandler(getProject(), true, false){
|
||||
new MockLocalToFieldHandler(getProject(), true, false) {
|
||||
@Override
|
||||
protected int getChosenClassIndex(List<PsiClass> classes) {
|
||||
return 0;
|
||||
@@ -47,6 +47,10 @@ public class IntroduceConstantTest extends LightJavaCodeInsightTestCase {
|
||||
checkResultByFile(BASE_PATH + getTestName(false) + "_after.java");
|
||||
}
|
||||
|
||||
public void testNonStaticContainerForCompileTimeConstant2() { doTest(); }
|
||||
public void testStaticFieldInAnonymous() { doTest(); }
|
||||
public void testStaticFieldInAnonymousJava8() { doTest(); }
|
||||
|
||||
private void doTest(boolean makeEnumConstant) {
|
||||
configureByFile(BASE_PATH + getTestName(false) + ".java");
|
||||
PsiLocalVariable local = PsiTreeUtil.getParentOfType(getFile().findElementAt(getEditor().getCaretModel().getOffset()), PsiLocalVariable.class);
|
||||
@@ -60,7 +64,7 @@ public class IntroduceConstantTest extends LightJavaCodeInsightTestCase {
|
||||
|
||||
public void testUnresolvedReferenceInEnum() {
|
||||
configureByFile(BASE_PATH + getTestName(false) + ".java");
|
||||
new MockIntroduceConstantHandler(null).invoke(getProject(), getEditor(), getFile(), null);
|
||||
new MockIntroduceConstantHandler(((PsiJavaFile)getFile()).getClasses()[0]).invoke(getProject(), getEditor(), getFile(), null);
|
||||
checkResultByFile(BASE_PATH + getTestName(false) + "_after.java");
|
||||
}
|
||||
|
||||
@@ -70,7 +74,7 @@ public class IntroduceConstantTest extends LightJavaCodeInsightTestCase {
|
||||
|
||||
public void testFromEnumConstantInitializer2() {
|
||||
configureByFile(BASE_PATH + getTestName(false) + ".java");
|
||||
new MockIntroduceConstantHandler(null).invoke(getProject(), getEditor(), getFile(), null);
|
||||
new MockIntroduceConstantHandler(((PsiJavaFile)getFile()).getClasses()[0]).invoke(getProject(), getEditor(), getFile(), null);
|
||||
checkResultByFile(BASE_PATH + getTestName(false) + "_after.java");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user