extract enum: do not migrate other constants to enum

This commit is contained in:
anna
2010-06-09 17:32:56 +04:00
parent bc85d6e3b9
commit a45cb23ea5
5 changed files with 84 additions and 35 deletions
@@ -30,7 +30,15 @@ import com.intellij.refactoring.typeMigration.TypeConversionDescriptorBase;
import com.intellij.refactoring.typeMigration.TypeMigrationLabeler;
import com.intellij.refactoring.typeMigration.rules.TypeConversionRule;
import java.util.List;
public class EnumTypeConversionRule extends TypeConversionRule {
private final List<PsiField> myEnumConstants;
public EnumTypeConversionRule(List<PsiField> enumConstants) {
myEnumConstants = enumConstants;
}
@Override
public TypeConversionDescriptorBase findConversion(PsiType from,
PsiType to,
@@ -47,6 +55,14 @@ public class EnumTypeConversionRule extends TypeConversionRule {
}
}
}
final PsiField field = PsiTreeUtil.getParentOfType(context, PsiField.class);
if (field != null &&
!myEnumConstants.contains(field) &&
field.hasModifierProperty(PsiModifier.STATIC) &&
field.hasModifierProperty(PsiModifier.FINAL) &&
field.hasInitializer()) {
return null;
}
final PsiClass toClass = PsiUtil.resolveClassInType(to);
if (toClass != null && toClass.isEnum()) {
final PsiMethod[] constructors = toClass.getConstructors();
@@ -70,9 +70,9 @@ public class ExtractEnumProcessor {
MutationUtils.replaceExpression(expression.getReferenceName() + "." + link, expression);
}
});
continue;
} else if (element != null) {
resolvableConflicts.add(new ConflictUsageInfo(element, null));
}
conflicts.putValue(element, "Failed to migrate");
}
if (!resolvableConflicts.isEmpty()) {
final List<UsageInfo> usageInfos = new ArrayList<UsageInfo>(Arrays.asList(refUsages.get()));
@@ -89,21 +89,6 @@ public class ExtractEnumProcessor {
refUsages.set(resolvableConflicts.toArray(new UsageInfo[resolvableConflicts.size()]));
}
}
for (final PsiField enumConstant : myEnumConstants) {
final PsiExpression initializer = enumConstant.getInitializer();
assert initializer != null;
initializer.accept(new JavaRecursiveElementWalkingVisitor() {
@Override
public void visitReferenceExpression(PsiReferenceExpression expression) {
super.visitReferenceExpression(expression);
final PsiElement resolved = expression.resolve();
if (!myEnumConstants.contains(resolved) && myFields.contains(resolved)) {
conflicts.putValue(initializer, "Enum constant " + RefactoringUIUtil.getDescription(enumConstant, false) +
" would forward reference on field " + RefactoringUIUtil.getDescription(resolved, false));
}
}
});
}
}
private boolean hasUsages2Migrate() {
@@ -132,7 +117,6 @@ public class ExtractEnumProcessor {
}
final PsiType enumValueType = myEnumConstants.get(0).getType();
final Set<PsiElement> toMigrate = new HashSet<PsiElement>();
for (PsiSwitchStatement switchStatement : switchStatements) {
final PsiStatement errStatement = EnumConstantsUtil.isEnumSwitch(switchStatement, enumValueType, enumValues);
if (errStatement != null) {
@@ -140,7 +124,7 @@ public class ExtractEnumProcessor {
if (errStatement instanceof PsiSwitchLabelStatement) {
final PsiExpression caseValue = ((PsiSwitchLabelStatement)errStatement).getCaseValue();
if (caseValue != null) {
description = caseValue.getText() + " can't be replaced with enum";
description = caseValue.getText() + " can not be replaced with enum";
}
}
result.add(new ConflictUsageInfo(errStatement, description));
@@ -154,9 +138,6 @@ public class ExtractEnumProcessor {
if (!element.getManager().isInProject(element)) {
result.add(new ConflictUsageInfo(expression, StringUtil.capitalize(RefactoringUIUtil.getDescription(element, false)) + " is out of project"));
}
else {
toMigrate.add(element);
}
}
}
else {
@@ -165,16 +146,24 @@ public class ExtractEnumProcessor {
}
}
if (!toMigrate.isEmpty()) {
final TypeMigrationRules rules = new TypeMigrationRules(this.myEnumConstants.get(0).getType());
rules.addConversionDescriptor(new EnumTypeConversionRule());
rules.setMigrationRootType(
JavaPsiFacade.getElementFactory(myProject).createType(myClass));
rules.setBoundScope(GlobalSearchScope.projectScope(myProject));
myTypeMigrationProcessor = new TypeMigrationProcessor(myProject, toMigrate.toArray(new PsiElement[toMigrate.size()]), rules);
for (UsageInfo usageInfo : myTypeMigrationProcessor.findUsages()) {
result.add(new EnumTypeMigrationUsageInfo(usageInfo));
final TypeMigrationRules rules = new TypeMigrationRules(myEnumConstants.get(0).getType());
rules.addConversionDescriptor(new EnumTypeConversionRule(myEnumConstants));
rules.setMigrationRootType(
JavaPsiFacade.getElementFactory(myProject).createType(myClass));
rules.setBoundScope(GlobalSearchScope.projectScope(myProject));
myTypeMigrationProcessor = new TypeMigrationProcessor(myProject, myEnumConstants.toArray(new PsiElement[myEnumConstants.size()]), rules);
for (UsageInfo usageInfo : myTypeMigrationProcessor.findUsages()) {
final PsiElement migrateElement = usageInfo.getElement();
if (migrateElement instanceof PsiField) {
final PsiField enumConstantField = (PsiField)migrateElement;
if (enumConstantField.hasModifierProperty(PsiModifier.STATIC) &&
enumConstantField.hasModifierProperty(PsiModifier.FINAL) &&
enumConstantField.hasInitializer() &&
!myEnumConstants.contains(enumConstantField)) {
continue;
}
}
result.add(new EnumTypeMigrationUsageInfo(usageInfo));
}
}
return result;
@@ -0,0 +1,19 @@
public class Test {
public static final int OK = 0;
public static final int ERROR = 1;
void foo(int status) {
switch (status) {
case OK:
break;
case ERROR:
break;
case Node.WARNING:
break;
}
}
}
interface Node {
int WARNING = 2;
}
@@ -0,0 +1,19 @@
public class Test {
public static final int OK = 0;
public static final int ERROR = 1;
void foo(int status) {
switch (status) {
case OK:
break;
case ERROR:
break;
case Node.WARNING:
break;
}
}
}
interface Node {
int WARNING = 2;
}
@@ -60,7 +60,7 @@ public class ExtractEnumTest extends MultiFileTestCase {
}
public void testForwardReferenceConflict() throws Exception {
doTest("Enum constant field <b><code>BAR</code></b> would forward reference on field field <b><code>FOO</code></b>", false,
doTest("Unable to migrate statement to enum constant.", false,
new RefactoringTestUtil.MemberDescriptor("FOO", PsiField.class, false),
new RefactoringTestUtil.MemberDescriptor("BAR", PsiField.class, true));
}
@@ -76,13 +76,19 @@ public class ExtractEnumTest extends MultiFileTestCase {
}
public void testCantChangeMethodParameter() throws Exception {
doTest("Failed to migrate", false,
doTest("Unable to migrate statement to enum constant.", false,
new RefactoringTestUtil.MemberDescriptor("FOO", PsiField.class, true),
new RefactoringTestUtil.MemberDescriptor("BAR", PsiField.class, true));
}
public void testDontChangeOtherConstants() throws Exception {
doTest("Unable to migrate statement to enum constant. Node.WARNING can not be replaced with enum", false,
new RefactoringTestUtil.MemberDescriptor("OK", PsiField.class, true),
new RefactoringTestUtil.MemberDescriptor("ERROR", PsiField.class, true));
}
public void testCantChangeMethodParameter1() throws Exception {
doTest("Failed to migrate", false,
doTest("Unable to migrate statement to enum constant.", false,
new RefactoringTestUtil.MemberDescriptor("FOO", PsiField.class, true),
new RefactoringTestUtil.MemberDescriptor("BAR", PsiField.class, true));
}
@@ -115,7 +121,7 @@ public class ExtractEnumTest extends MultiFileTestCase {
}
public void testUnknownSwitchLabel() throws Exception {
doTest("Unable to migrate statement to enum constant. 8 can&apos;t be replaced with enum", false,
doTest("Unable to migrate statement to enum constant. 8 can not be replaced with enum", false,
new RefactoringTestUtil.MemberDescriptor("FOO", PsiField.class, true),
new RefactoringTestUtil.MemberDescriptor("BAR", PsiField.class, true));
}