type migration: multiple declaration IDEA-154937 initial

This commit is contained in:
Dmitry Batkovich
2016-05-05 15:15:25 +03:00
parent b05ba7026f
commit 23cf1ec215
6 changed files with 56 additions and 29 deletions
@@ -27,9 +27,10 @@ import com.intellij.refactoring.RefactoringActionHandler;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.typeMigration.ui.TypeMigrationDialog;
import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.intellij.util.Function;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
public class ChangeTypeSignatureHandler implements RefactoringActionHandler {
private static final Logger LOG = Logger.getInstance("#" + ChangeTypeSignatureHandler.class.getName());
@@ -42,8 +43,15 @@ public class ChangeTypeSignatureHandler implements RefactoringActionHandler {
PsiTypeElement typeElement = PsiTreeUtil.getParentOfType(element, PsiTypeElement.class);
while (typeElement != null) {
final PsiElement parent = typeElement.getParent();
if (parent instanceof PsiVariable || (parent instanceof PsiMember && !(parent instanceof PsiClass)) || isClassArgument(parent)) {
invoke(project, parent, null, null, editor);
PsiElement[] toMigrate = null;
if (parent instanceof PsiVariable) {
toMigrate = extractReferencedVariables(typeElement);
}
else if ((parent instanceof PsiMember && !(parent instanceof PsiClass)) || isClassArgument(parent)) {
toMigrate = new PsiElement[]{parent};
}
if (toMigrate != null && toMigrate.length > 0) {
invoke(project, toMigrate, null, null, editor);
return;
}
typeElement = PsiTreeUtil.getParentOfType(parent, PsiTypeElement.class, false);
@@ -61,12 +69,11 @@ public class ChangeTypeSignatureHandler implements RefactoringActionHandler {
}
public static boolean invokeOnElement(final Project project, final PsiElement element) {
if (element instanceof PsiVariable || (element instanceof PsiMember && !(element instanceof PsiClass)) || element instanceof PsiFile) {
invoke(project, element, null, null, null);
return true;
}
if (isClassArgument(element)) {
invoke(project, element, null, null, null);
if (element instanceof PsiVariable ||
(element instanceof PsiMember && !(element instanceof PsiClass)) ||
element instanceof PsiFile ||
isClassArgument(element)) {
invoke(project, new PsiElement[] {element}, null, null, null);
return true;
}
return false;
@@ -88,9 +95,9 @@ public class ChangeTypeSignatureHandler implements RefactoringActionHandler {
return false;
}
public static void invoke(final Project project, final PsiElement root, final PsiType type, final TypeMigrationRules rules, final Editor editor) {
if (Util.canBeMigrated(root)) {
TypeMigrationDialog dialog = new TypeMigrationDialog.SingleElement(project, root, type, rules);
public static void invoke(final Project project, final PsiElement[] roots, final PsiType type, final TypeMigrationRules rules, final Editor editor) {
if (Util.canBeMigrated(roots)) {
TypeMigrationDialog dialog = new TypeMigrationDialog.SingleElement(project, roots, type, rules);
dialog.show();
return;
}
@@ -99,4 +106,14 @@ public class ChangeTypeSignatureHandler implements RefactoringActionHandler {
RefactoringBundle.message("unable.to.start.type.migration"), null);
}
@NotNull
private static PsiElement[] extractReferencedVariables(PsiTypeElement typeElement) {
final PsiDeclarationStatement declaration = PsiTreeUtil.getParentOfType(typeElement, PsiDeclarationStatement.class);
if (declaration == null) return PsiElement.EMPTY_ARRAY;
return Arrays.stream(declaration.getDeclaredElements())
.filter(PsiVariable.class::isInstance)
.filter(e -> ((PsiVariable)e).getTypeElement() == typeElement)
.toArray(PsiElement[]::new);
}
}
@@ -304,7 +304,9 @@ public class TypeMigrationLabeler {
myRemainConversions = conversions;
}
public void change(final TypeMigrationUsageInfo usageInfo, @NotNull Consumer<PsiNewExpression> consumer) {
public void change(@NotNull final TypeMigrationUsageInfo usageInfo,
@NotNull Consumer<PsiNewExpression> consumer,
@NotNull TypeMigrationLabeler labeler) {
final PsiElement element = usageInfo.getElement();
if (element == null) return;
final Project project = element.getProject();
@@ -341,7 +343,7 @@ public class TypeMigrationLabeler {
}
}
else {
TypeMigrationReplacementUtil.migratePsiMemberType(element, project, getTypeEvaluator().getType(usageInfo));
TypeMigrationReplacementUtil.migrateMemberOrVariableType(element, project, getTypeEvaluator().getType(usageInfo));
if (usageInfo instanceof OverridenUsageInfo) {
final String migrationName = ((OverridenUsageInfo)usageInfo).getMigrateMethodName();
if (migrationName != null) {
@@ -248,7 +248,7 @@ public class TypeMigrationProcessor extends BaseRefactoringProcessor {
final TypeMigrationLabeler.MigrationProducer producer = labeler.createMigratorFor(usages);
final SmartPointerManager smartPointerManager = SmartPointerManager.getInstance(project);
List<UsageInfo> nonCodeUsages = new ArrayList<UsageInfo>();
List<UsageInfo> nonCodeUsages = new ArrayList<>();
for (UsageInfo usage : usages) {
if (((TypeMigrationUsageInfo)usage).isExcluded()) continue;
final PsiElement element = usage.getElement();
@@ -256,12 +256,9 @@ public class TypeMigrationProcessor extends BaseRefactoringProcessor {
element instanceof PsiMember ||
element instanceof PsiExpression ||
element instanceof PsiReferenceParameterList) {
producer.change((TypeMigrationUsageInfo)usage, new Consumer<PsiNewExpression>() {
@Override
public void consume(@NotNull PsiNewExpression expression) {
newExpressionsToCheckDiamonds.add(smartPointerManager.createSmartPsiElementPointer(expression));
}
});
producer.change((TypeMigrationUsageInfo)usage,
expression -> newExpressionsToCheckDiamonds.add(smartPointerManager.createSmartPsiElementPointer(expression)),
labeler);
}
else {
nonCodeUsages.add(usage);
@@ -114,7 +114,7 @@ public class TypeMigrationReplacementUtil {
return expression;
}
static void migratePsiMemberType(final PsiElement element, final Project project, PsiType migratedType) {
static void migrateMemberOrVariableType(final PsiElement element, final Project project, PsiType migratedType) {
try {
if (!migratedType.isValid()) {
migratedType = JavaPsiFacade.getElementFactory(project).createTypeByFQClassName(migratedType.getCanonicalText());
@@ -19,6 +19,7 @@ import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.SmartList;
import com.intellij.util.containers.Queue;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
@@ -91,7 +92,16 @@ public class Util {
return element;
}
public static boolean canBeMigrated(final PsiElement e) {
public static boolean canBeMigrated(@NotNull final PsiElement[] es) {
for (PsiElement e : es) {
if (!canBeMigrated(e)) {
return false;
}
}
return true;
}
private static boolean canBeMigrated(@Nullable final PsiElement e) {
if (e == null) {
return false;
}
@@ -116,8 +126,7 @@ public class Util {
return aClass != null;
}
else if (elementType instanceof PsiDisjunctionType) {
final PsiType lub = ((PsiDisjunctionType)elementType).getLeastUpperBound();
return lub != null;
return true;
}
}
@@ -59,7 +59,7 @@ import java.util.List;
* Date: 25-Mar-2008
*/
public abstract class TypeMigrationDialog extends RefactoringDialog {
private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.typeMigration.ui.TypeMigrationDialog");
private static final Logger LOG = Logger.getInstance(TypeMigrationDialog.class);
public static final String REFACTORING_NAME = "Type Migration";
@@ -68,7 +68,7 @@ public abstract class TypeMigrationDialog extends RefactoringDialog {
private final ScopeChooserCombo myScopeChooserCombo;
public TypeMigrationDialog(@NotNull Project project,
PsiElement roots[],
PsiElement[] roots,
TypeMigrationRules rules) {
super(project, false);
myRoots = roots;
@@ -150,14 +150,16 @@ public abstract class TypeMigrationDialog extends RefactoringDialog {
private final EditorComboBox myToTypeEditor;
public SingleElement(@NotNull Project project,
PsiElement root,
PsiElement[] roots,
PsiType migrationType,
TypeMigrationRules rules) {
super(project, new PsiElement[]{root}, rules);
super(project, roots, rules);
LOG.assertTrue(roots.length > 0);
final PsiType rootType = getRootType();
final String text = migrationType != null ? migrationType.getCanonicalText(true) :
rootType != null ? rootType.getCanonicalText(true) : "";
int flags = 0;
PsiElement root = roots[0];
if (root instanceof PsiParameter) {
final PsiElement scope = ((PsiParameter)root).getDeclarationScope();
if (scope instanceof PsiMethod) {