inline field: collect final field initializers in constructors (IDEA-130350)

This commit is contained in:
Anna.Kozlova
2016-04-27 15:16:57 +02:00
parent ccb2710190
commit cafbadc4d2
6 changed files with 114 additions and 10 deletions
@@ -15,6 +15,7 @@
*/
package com.intellij.refactoring.inline;
import com.intellij.codeInsight.PsiEquivalenceUtil;
import com.intellij.codeInsight.TargetElementUtil;
import com.intellij.lang.StdLanguages;
import com.intellij.openapi.application.ApplicationManager;
@@ -23,12 +24,19 @@ import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.*;
import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.search.ProjectScope;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.refactoring.HelpID;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
* @author ven
@@ -46,7 +54,7 @@ public class InlineConstantFieldHandler extends JavaInlineActionHandler {
final PsiElement navigationElement = element.getNavigationElement();
final PsiField field = (PsiField)(navigationElement instanceof PsiField ? navigationElement : element);
if (!field.hasInitializer()) {
if (getInitializer(field) == null) {
String message = RefactoringBundle.message("no.initializer.present.for.the.field");
CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, HelpID.INLINE_FIELD);
return;
@@ -97,4 +105,40 @@ public class InlineConstantFieldHandler extends JavaInlineActionHandler {
InlineFieldDialog dialog = new InlineFieldDialog(project, field, refExpression);
dialog.show();
}
@Nullable
protected static PsiExpression getInitializer(PsiField field) {
if (field.hasInitializer()) {
return field.getInitializer();
}
if (field.hasModifierProperty(PsiModifier.FINAL)) {
PsiClass containingClass = field.getContainingClass();
if (containingClass != null) {
PsiMethod[] constructors = containingClass.getConstructors();
final List<PsiExpression> result = new ArrayList<>();
for (PsiReference reference : ReferencesSearch.search(field, new LocalSearchScope(constructors))) {
final PsiElement element = reference.getElement();
if (element instanceof PsiReferenceExpression && PsiUtil.isOnAssignmentLeftHand((PsiExpression)element)) {
PsiAssignmentExpression assignmentExpression = PsiTreeUtil.getParentOfType(element, PsiAssignmentExpression.class);
if (assignmentExpression != null) {
ContainerUtil.addIfNotNull(assignmentExpression.getRExpression(), result);
}
}
}
if (result.isEmpty()) return null;
PsiExpression first = result.get(0);
for (PsiExpression expr : result) {
if (!PsiEquivalenceUtil.areElementsEquivalent(expr, first)) {
return null;
}
}
return first;
}
}
return null;
}
}
@@ -137,7 +137,7 @@ public class InlineConstantFieldProcessor extends BaseRefactoringProcessor {
@Override
protected void performRefactoring(@NotNull UsageInfo[] usages) {
PsiExpression initializer = myField.getInitializer();
PsiExpression initializer = InlineConstantFieldHandler.getInitializer(myField);
LOG.assertTrue(initializer != null);
initializer = normalize ((PsiExpression)initializer.copy());
@@ -190,13 +190,23 @@ public class InlineConstantFieldProcessor extends BaseRefactoringProcessor {
if (myField.isWritable()) {
myField.normalizeDeclaration();
}
if (isAccessedForWriting(expr)) {
PsiAssignmentExpression assignmentExpression = PsiTreeUtil.getParentOfType(expr, PsiAssignmentExpression.class);
if (assignmentExpression != null) {
assignmentExpression.delete();
}
return;
}
if (expr instanceof PsiReferenceExpression) {
PsiExpression qExpression = ((PsiReferenceExpression)expr).getQualifierExpression();
if (qExpression != null) {
PsiReferenceExpression referenceExpression = null;
if (initializer1 instanceof PsiReferenceExpression) {
referenceExpression = (PsiReferenceExpression)initializer1;
} else if (initializer1 instanceof PsiMethodCallExpression) {
}
else if (initializer1 instanceof PsiMethodCallExpression) {
referenceExpression = ((PsiMethodCallExpression)initializer1).getMethodExpression();
}
if (referenceExpression != null &&
@@ -242,7 +252,7 @@ public class InlineConstantFieldProcessor extends BaseRefactoringProcessor {
MultiMap<PsiElement, String> conflicts = new MultiMap<PsiElement, String>();
ReferencedElementsCollector collector = new ReferencedElementsCollector();
PsiExpression initializer = myField.getInitializer();
PsiExpression initializer = InlineConstantFieldHandler.getInitializer(myField);
LOG.assertTrue(initializer != null);
initializer.accept(collector);
HashSet<PsiMember> referencedWithVisibility = collector.myReferencedMembers;
@@ -250,7 +260,7 @@ public class InlineConstantFieldProcessor extends BaseRefactoringProcessor {
PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(myField.getProject()).getResolveHelper();
for (UsageInfo info : usagesIn) {
PsiElement element = info.getElement();
if (element instanceof PsiExpression && isAccessedForWriting((PsiExpression)element)) {
if (element instanceof PsiExpression && (!myField.hasModifierProperty(PsiModifier.FINAL) || myInlineThisOnly) && isAccessedForWriting((PsiExpression)element)) {
String message = RefactoringBundle.message("0.is.used.for.writing.in.1", RefactoringUIUtil.getDescription(myField, true),
RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(element), true));
conflicts.putValue(element, message);
@@ -0,0 +1,15 @@
class Test {
private final int <caret>i;
public Test() {
this.i = 0;
}
public Test(String s) {
this.i = 0;
}
void foo() {
System.out.println(i);
}
}
@@ -0,0 +1,12 @@
class Test {
public Test() {
}
public Test(String s) {
}
void foo() {
System.out.println(0);
}
}
@@ -0,0 +1,15 @@
class Test {
private final int <caret>i;
public Test() {
this.i = 0;
}
public Test(String s) {
this.i = s.length();
}
void foo() {
System.out.println(i);
}
}
@@ -38,15 +38,22 @@ public class InlineConstantFieldTest extends LightRefactoringTestCase {
doTest();
}
public void testFinalInitializedInConstructor() throws Exception {
doTest();
}
public void testMultipleInitializers() throws Exception {
configureByFile("/refactoring/inlineConstantField/" + getTestName(false) + ".java");
PsiElement element = TargetElementUtil
.findTargetElement(myEditor, TargetElementUtil.ELEMENT_NAME_ACCEPTED | TargetElementUtil.REFERENCED_ELEMENT_ACCEPTED);
assertTrue(element instanceof PsiField);
assertNull(InlineConstantFieldHandler.getInitializer((PsiField)element));
}
private void doTest() throws Exception {
String name = getTestName(false);
@NonNls String fileName = "/refactoring/inlineConstantField/" + name + ".java";
configureByFile(fileName);
performAction();
checkResultByFile(fileName + ".after");
}
private void performAction() {
PsiElement element = TargetElementUtil
.findTargetElement(myEditor, TargetElementUtil.ELEMENT_NAME_ACCEPTED | TargetElementUtil.REFERENCED_ELEMENT_ACCEPTED);
final PsiReference ref = myFile.findReferenceAt(myEditor.getCaretModel().getOffset());
@@ -54,5 +61,6 @@ public class InlineConstantFieldTest extends LightRefactoringTestCase {
assertTrue(element instanceof PsiField);
PsiField field = (PsiField)element.getNavigationElement();
new InlineConstantFieldProcessor(field, getProject(), refExpr, element instanceof PsiCompiledElement).run();
checkResultByFile(fileName + ".after");
}
}