mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
extract field: allow to extract static field from super/this calls (IDEA-197438)
This commit is contained in:
+86
-1
@@ -18,6 +18,7 @@ package com.intellij.refactoring.introduceField;
|
||||
|
||||
import com.intellij.codeInsight.AnnotationUtil;
|
||||
import com.intellij.codeInsight.ChangeContextUtil;
|
||||
import com.intellij.codeInsight.ExceptionUtil;
|
||||
import com.intellij.codeInsight.TestFrameworks;
|
||||
import com.intellij.codeInsight.daemon.impl.quickfix.AnonymousTargetClassPreselectionUtil;
|
||||
import com.intellij.codeInsight.highlighting.HighlightManager;
|
||||
@@ -57,6 +58,7 @@ import com.intellij.refactoring.util.CommonRefactoringUtil;
|
||||
import com.intellij.refactoring.util.EnumConstantsUtil;
|
||||
import com.intellij.refactoring.util.RefactoringChangeUtil;
|
||||
import com.intellij.refactoring.util.RefactoringUtil;
|
||||
import com.intellij.refactoring.util.classMembers.ClassMemberReferencesVisitor;
|
||||
import com.intellij.refactoring.util.occurrences.OccurrenceManager;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.VisibilityUtil;
|
||||
@@ -181,8 +183,12 @@ public abstract class BaseExpressionToFieldHandler extends IntroduceHandlerBase
|
||||
|
||||
PsiElement tempAnchorElement = RefactoringUtil.getParentExpressionAnchorElement(selectedExpr);
|
||||
if (!Comparing.strEqual(IntroduceConstantHandler.REFACTORING_NAME, getRefactoringName()) &&
|
||||
IntroduceVariableBase.checkAnchorBeforeThisOrSuper(project, editor, tempAnchorElement, getRefactoringName(), getHelpID()))
|
||||
IntroduceFieldHandler.isInSuperOrThis(selectedExpr) &&
|
||||
isStaticFinalInitializer(selectedExpr) != null) {
|
||||
String message = RefactoringBundle.getCannotRefactorMessage(RefactoringBundle.message("invalid.expression.context"));
|
||||
CommonRefactoringUtil.showErrorHint(project, editor, message, getRefactoringName(), getHelpID());
|
||||
return true;
|
||||
}
|
||||
|
||||
final Settings settings =
|
||||
showRefactoringDialog(project, editor, myParentClass, selectedExpr, tempType,
|
||||
@@ -245,6 +251,15 @@ public abstract class BaseExpressionToFieldHandler extends IntroduceHandlerBase
|
||||
);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected PsiElement isStaticFinalInitializer(PsiExpression expr) {
|
||||
PsiClass parentClass = expr != null ? getParentClass(expr) : null;
|
||||
if (parentClass == null) return null;
|
||||
IsStaticFinalInitializerExpression visitor = new IsStaticFinalInitializerExpression(parentClass, expr);
|
||||
expr.accept(visitor);
|
||||
return visitor.getElementReference();
|
||||
}
|
||||
|
||||
protected abstract OccurrenceManager createOccurrenceManager(PsiExpression selectedExpr, PsiClass parentClass);
|
||||
|
||||
protected final PsiClass getParentClass() {
|
||||
@@ -925,4 +940,74 @@ public abstract class BaseExpressionToFieldHandler extends IntroduceHandlerBase
|
||||
return myField;
|
||||
}
|
||||
}
|
||||
|
||||
private static class IsStaticFinalInitializerExpression extends ClassMemberReferencesVisitor {
|
||||
private PsiElement myElementReference;
|
||||
private final PsiExpression myInitializer;
|
||||
private boolean myCheckThrowables = true;
|
||||
|
||||
public IsStaticFinalInitializerExpression(PsiClass aClass, PsiExpression initializer) {
|
||||
super(aClass);
|
||||
myInitializer = initializer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReferenceExpression(PsiReferenceExpression expression) {
|
||||
final PsiElement psiElement = expression.resolve();
|
||||
if ((psiElement instanceof PsiLocalVariable || psiElement instanceof PsiParameter) &&
|
||||
!PsiTreeUtil.isAncestor(myInitializer, psiElement, false)) {
|
||||
myElementReference = expression;
|
||||
}
|
||||
else {
|
||||
super.visitReferenceExpression(expression);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodReferenceExpression(PsiMethodReferenceExpression expression) {
|
||||
if (!PsiMethodReferenceUtil.isResolvedBySecondSearch(expression)) {
|
||||
super.visitMethodReferenceExpression(expression);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCallExpression(PsiCallExpression callExpression) {
|
||||
super.visitCallExpression(callExpression);
|
||||
if (!myCheckThrowables) return;
|
||||
final List<PsiClassType> checkedExceptions = ExceptionUtil.getThrownCheckedExceptions(callExpression);
|
||||
if (!checkedExceptions.isEmpty()) {
|
||||
myElementReference = callExpression;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitClass(PsiClass aClass) {
|
||||
myCheckThrowables = false;
|
||||
super.visitClass(aClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLambdaExpression(PsiLambdaExpression expression) {
|
||||
myCheckThrowables = false;
|
||||
super.visitLambdaExpression(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void visitClassMemberReferenceElement(PsiMember classMember, PsiJavaCodeReferenceElement classMemberReference) {
|
||||
if (!classMember.hasModifierProperty(PsiModifier.STATIC)) {
|
||||
myElementReference = classMemberReference;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitElement(PsiElement element) {
|
||||
if (myElementReference != null) return;
|
||||
super.visitElement(element);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PsiElement getElementReference() {
|
||||
return myElementReference;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-83
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package com.intellij.refactoring.introduceField;
|
||||
|
||||
import com.intellij.codeInsight.ExceptionUtil;
|
||||
import com.intellij.codeInsight.highlighting.HighlightManager;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
@@ -34,14 +33,11 @@ import com.intellij.refactoring.introduce.inplace.AbstractInplaceIntroducer;
|
||||
import com.intellij.refactoring.ui.TypeSelectorManagerImpl;
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil;
|
||||
import com.intellij.refactoring.util.RefactoringUtil;
|
||||
import com.intellij.refactoring.util.classMembers.ClassMemberReferencesVisitor;
|
||||
import com.intellij.refactoring.util.occurrences.ExpressionOccurrenceManager;
|
||||
import com.intellij.refactoring.util.occurrences.OccurrenceManager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class IntroduceConstantHandler extends BaseExpressionToFieldHandler {
|
||||
public static final String REFACTORING_NAME = RefactoringBundle.message("introduce.constant.title");
|
||||
@@ -212,90 +208,11 @@ public class IntroduceConstantHandler extends BaseExpressionToFieldHandler {
|
||||
return myInplaceIntroduceConstantPopup;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PsiElement isStaticFinalInitializer(PsiExpression expr) {
|
||||
PsiClass parentClass = expr != null ? getParentClass(expr) : null;
|
||||
if (parentClass == null) return null;
|
||||
IsStaticFinalInitializerExpression visitor = new IsStaticFinalInitializerExpression(parentClass, expr);
|
||||
expr.accept(visitor);
|
||||
return visitor.getElementReference();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected OccurrenceManager createOccurrenceManager(final PsiExpression selectedExpr, final PsiClass parentClass) {
|
||||
return new ExpressionOccurrenceManager(selectedExpr, parentClass, null);
|
||||
}
|
||||
|
||||
private static class IsStaticFinalInitializerExpression extends ClassMemberReferencesVisitor {
|
||||
private PsiElement myElementReference;
|
||||
private final PsiExpression myInitializer;
|
||||
private boolean myCheckThrowables = true;
|
||||
|
||||
public IsStaticFinalInitializerExpression(PsiClass aClass, PsiExpression initializer) {
|
||||
super(aClass);
|
||||
myInitializer = initializer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReferenceExpression(PsiReferenceExpression expression) {
|
||||
final PsiElement psiElement = expression.resolve();
|
||||
if ((psiElement instanceof PsiLocalVariable || psiElement instanceof PsiParameter) &&
|
||||
!PsiTreeUtil.isAncestor(myInitializer, psiElement, false)) {
|
||||
myElementReference = expression;
|
||||
}
|
||||
else {
|
||||
super.visitReferenceExpression(expression);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodReferenceExpression(PsiMethodReferenceExpression expression) {
|
||||
if (!PsiMethodReferenceUtil.isResolvedBySecondSearch(expression)) {
|
||||
super.visitMethodReferenceExpression(expression);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCallExpression(PsiCallExpression callExpression) {
|
||||
super.visitCallExpression(callExpression);
|
||||
if (!myCheckThrowables) return;
|
||||
final List<PsiClassType> checkedExceptions = ExceptionUtil.getThrownCheckedExceptions(callExpression);
|
||||
if (!checkedExceptions.isEmpty()) {
|
||||
myElementReference = callExpression;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitClass(PsiClass aClass) {
|
||||
myCheckThrowables = false;
|
||||
super.visitClass(aClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLambdaExpression(PsiLambdaExpression expression) {
|
||||
myCheckThrowables = false;
|
||||
super.visitLambdaExpression(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void visitClassMemberReferenceElement(PsiMember classMember, PsiJavaCodeReferenceElement classMemberReference) {
|
||||
if (!classMember.hasModifierProperty(PsiModifier.STATIC)) {
|
||||
myElementReference = classMemberReference;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitElement(PsiElement element) {
|
||||
if (myElementReference != null) return;
|
||||
super.visitElement(element);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PsiElement getElementReference() {
|
||||
return myElementReference;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiClass getParentClass(@NotNull PsiExpression initializerExpression) {
|
||||
final PsiType type = initializerExpression.getType();
|
||||
|
||||
+4
-3
@@ -87,7 +87,7 @@ public abstract class IntroduceFieldCentralPanel {
|
||||
myTypeSelectorManager = typeSelectorManager;
|
||||
}
|
||||
|
||||
protected boolean setEnabledInitializationPlaces(@NotNull final PsiElement initializer) {
|
||||
protected boolean setEnabledInitializationPlaces(@NotNull final PsiExpression initializer) {
|
||||
final Set<PsiField> fields = new HashSet<>();
|
||||
final Ref<Boolean> refsLocal = new Ref<>(false);
|
||||
initializer.accept(new JavaRecursiveElementWalkingVisitor() {
|
||||
@@ -113,11 +113,12 @@ public abstract class IntroduceFieldCentralPanel {
|
||||
});
|
||||
|
||||
final boolean locals = refsLocal.get();
|
||||
if (!locals && fields.isEmpty()) {
|
||||
boolean superOrThis = IntroduceFieldHandler.isInSuperOrThis(initializer);
|
||||
if (!locals && fields.isEmpty() && !superOrThis) {
|
||||
return true;
|
||||
}
|
||||
return updateInitializationPlaceModel(!locals && initializedInSetUp(fields),
|
||||
!locals && initializedInConstructor(fields));
|
||||
!locals && !superOrThis && initializedInConstructor(fields));
|
||||
}
|
||||
|
||||
private static boolean initializedInConstructor(Set<PsiField> fields) {
|
||||
|
||||
+1
-1
@@ -174,7 +174,7 @@ public class IntroduceFieldHandler extends BaseExpressionToFieldHandler {
|
||||
return myInplaceIntroduceFieldPopup;
|
||||
}
|
||||
|
||||
private static boolean isInSuperOrThis(PsiExpression occurrence) {
|
||||
static boolean isInSuperOrThis(PsiExpression occurrence) {
|
||||
return !NotInSuperCallOccurrenceFilter.INSTANCE.isOK(occurrence) || !NotInThisCallFilter.INSTANCE.isOK(occurrence);
|
||||
}
|
||||
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
class Test {
|
||||
public static final String foo = "foo";
|
||||
|
||||
Test(String s) {}
|
||||
Test() {
|
||||
this(foo);
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
class Test {
|
||||
Test(String s) {}
|
||||
Test() {
|
||||
this(<selection>"foo"</selection>);
|
||||
}
|
||||
}
|
||||
+6
@@ -154,6 +154,12 @@ public class IntroduceFieldInSameClassTest extends LightCodeInsightTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
public void testAcceptIntroduceFieldFromExprInThisCall() {
|
||||
configureByFile("beforeAcceptIntroduceFieldFromExprInThisCall.java");
|
||||
performRefactoring(BaseExpressionToFieldHandler.InitializationPlace.IN_FIELD_DECLARATION, true);
|
||||
checkResultByFile("afterAcceptIntroduceFieldFromExprInThisCall.java");
|
||||
}
|
||||
|
||||
public void testInConstructorEnclosingAnonymous() {
|
||||
configureByFile("beforeEnclosingAnonymous.java");
|
||||
performRefactoring(BaseExpressionToFieldHandler.InitializationPlace.IN_CONSTRUCTOR, false);
|
||||
|
||||
Reference in New Issue
Block a user