migration: ensure migrated refs are shortened (IDEA-163298)

This commit is contained in:
Anna.Kozlova
2016-10-31 16:20:47 +01:00
parent d9e89c1177
commit bed1e83f3d
7 changed files with 83 additions and 55 deletions

View File

@@ -22,17 +22,19 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMigration;
import com.intellij.psi.SmartPsiElementPointer;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.impl.migration.PsiMigrationManager;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.refactoring.BaseRefactoringProcessor;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.RefactoringHelper;
import com.intellij.usageView.UsageInfo;
import com.intellij.usageView.UsageViewDescriptor;
import org.jetbrains.annotations.NotNull;
@@ -48,6 +50,7 @@ public class MigrationProcessor extends BaseRefactoringProcessor {
private static final String REFACTORING_NAME = RefactoringBundle.message("migration.title");
private PsiMigration myPsiMigration;
private final GlobalSearchScope mySearchScope;
private ArrayList<SmartPsiElementPointer<PsiElement>> myRefsToShorten;
public MigrationProcessor(Project project, MigrationMap migrationMap) {
this(project, migrationMap, GlobalSearchScope.projectScope(project));
@@ -142,21 +145,22 @@ public class MigrationProcessor extends BaseRefactoringProcessor {
final PsiMigration psiMigration = PsiMigrationManager.getInstance(myProject).startMigration();
LocalHistoryAction a = LocalHistory.getInstance().startAction(getCommandName());
myRefsToShorten = new ArrayList<>();
try {
boolean sameShortNames = false;
for (int i = 0; i < myMigrationMap.getEntryCount(); i++) {
MigrationMapEntry entry = myMigrationMap.getEntryAt(i);
if (entry.getType() == MigrationMapEntry.PACKAGE) {
MigrationUtil.doPackageMigration(myProject, psiMigration, entry.getNewName(), usages);
}
if (entry.getType() == MigrationMapEntry.CLASS) {
MigrationUtil.doClassMigration(myProject, psiMigration, entry.getNewName(), usages);
String newName = entry.getNewName();
PsiElement element = entry.getType() == MigrationMapEntry.PACKAGE ? MigrationUtil.findOrCreatePackage(myProject, psiMigration, newName)
: MigrationUtil.findOrCreateClass(myProject, psiMigration, newName);
MigrationUtil.doMigration(element, newName, usages, myRefsToShorten);
if (!sameShortNames && Comparing.strEqual(StringUtil.getShortName(entry.getOldName()), StringUtil.getShortName(entry.getNewName()))) {
sameShortNames = true;
}
}
for(RefactoringHelper helper: Extensions.getExtensions(RefactoringHelper.EP_NAME)) {
Object preparedData = helper.prepareOperation(usages);
//noinspection unchecked
helper.performOperation(myProject, preparedData);
if (!sameShortNames) {
myRefsToShorten.clear();
}
}
finally {
@@ -166,6 +170,17 @@ public class MigrationProcessor extends BaseRefactoringProcessor {
}
@Override
protected void performPsiSpoilingRefactoring() {
JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(myProject);
for (SmartPsiElementPointer<PsiElement> pointer : myRefsToShorten) {
PsiElement element = pointer.getElement();
if (element != null) {
styleManager.shortenClassReferences(element);
}
}
}
protected String getCommandName() {
return REFACTORING_NAME;
}

View File

@@ -38,56 +38,29 @@ public class MigrationUtil {
public static UsageInfo[] findPackageUsages(Project project, PsiMigration migration, String qName, GlobalSearchScope searchScope) {
PsiPackage aPackage = findOrCreatePackage(project, migration, qName);
return findRefs(project, aPackage, searchScope);
return findRefs(aPackage, searchScope);
}
public static void doPackageMigration(Project project, PsiMigration migration, String newQName, UsageInfo[] usages) {
try {
PsiPackage aPackage = findOrCreatePackage(project, migration, newQName);
// rename all references
for (UsageInfo usage : usages) {
if (usage instanceof MigrationProcessor.MigrationUsageInfo) {
final MigrationProcessor.MigrationUsageInfo usageInfo = (MigrationProcessor.MigrationUsageInfo)usage;
if (Comparing.equal(newQName, usageInfo.mapEntry.getNewName())) {
PsiElement element = usage.getElement();
if (element == null || !element.isValid()) continue;
if (element instanceof PsiJavaCodeReferenceElement) {
((PsiJavaCodeReferenceElement)element).bindToElement(aPackage);
}
else {
bindNonJavaReference(aPackage, element, usage);
}
}
}
}
}
catch (IncorrectOperationException e) {
// should not happen!
LOG.error(e);
}
}
private static void bindNonJavaReference(PsiElement bindTo, PsiElement element, UsageInfo usage) {
private static PsiElement bindNonJavaReference(PsiElement bindTo, PsiElement element, UsageInfo usage) {
final TextRange range = usage.getRangeInElement();
for (PsiReference reference : element.getReferences()) {
if (reference instanceof JavaClassReference) {
final JavaClassReference classReference = (JavaClassReference)reference;
if (classReference.getRangeInElement().equals(range)) {
classReference.bindToElement(bindTo);
break;
return classReference.bindToElement(bindTo);
}
}
}
return bindTo;
}
public static UsageInfo[] findClassUsages(Project project, PsiMigration migration, String qName, GlobalSearchScope searchScope) {
PsiClass aClass = findOrCreateClass(project, migration, qName);
return findRefs(project, aClass, searchScope);
return findRefs(aClass, searchScope);
}
private static UsageInfo[] findRefs(final Project project, final PsiElement aClass, GlobalSearchScope searchScope) {
private static UsageInfo[] findRefs(final PsiElement aClass, GlobalSearchScope searchScope) {
final ArrayList<UsageInfo> results = new ArrayList<>();
for (PsiReference usage : ReferencesSearch.search(aClass, searchScope, false)) {
results.add(new UsageInfo(usage));
@@ -96,10 +69,9 @@ public class MigrationUtil {
return results.toArray(new UsageInfo[results.size()]);
}
public static void doClassMigration(Project project, PsiMigration migration, String newQName, UsageInfo[] usages) {
static void doMigration(PsiElement elementToBind, String newQName, UsageInfo[] usages, ArrayList<SmartPsiElementPointer<PsiElement>> refsToShorten) {
try {
PsiClass aClass = findOrCreateClass(project, migration, newQName);
SmartPointerManager smartPointerManager = SmartPointerManager.getInstance(elementToBind.getProject());
// rename all references
for (UsageInfo usage : usages) {
if (usage instanceof MigrationProcessor.MigrationUsageInfo) {
@@ -107,15 +79,17 @@ public class MigrationUtil {
if (Comparing.equal(newQName, usageInfo.mapEntry.getNewName())) {
PsiElement element = usage.getElement();
if (element == null || !element.isValid()) continue;
PsiElement psiElement;
if (element instanceof PsiJavaCodeReferenceElement) {
final PsiJavaCodeReferenceElement referenceElement = (PsiJavaCodeReferenceElement)element;
referenceElement.bindToElement(aClass);
psiElement = ((PsiJavaCodeReferenceElement)element).bindToElement(elementToBind);
}
else {
bindNonJavaReference(aClass, element, usage);
psiElement = bindNonJavaReference(elementToBind, element, usage);
}
if (psiElement != null) {
refsToShorten.add(smartPointerManager.createSmartPsiElementPointer(psiElement));
}
}
}
}
}

View File

@@ -0,0 +1,10 @@
import aaa.*;
import bbb.Test;
public class C {
@Test
void foo(){}
@Test
void bar(){}
}

View File

@@ -0,0 +1,8 @@
import bbb.Test;
public class C1 {
@Test
void foo(){}
@Test
void bar(){}
}

View File

@@ -0,0 +1,8 @@
import aaa.*;
public class C {
@Test
void foo(){}
@Test
void bar(){}
}

View File

@@ -0,0 +1,8 @@
import aaa.Test;
public class C1 {
@Test
void foo(){}
@Test
void bar(){}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,10 +15,9 @@
*/
package com.intellij.refactoring.migration;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.refactoring.MultiFileTestCase;
import com.intellij.JavaTestUtil;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.refactoring.MultiFileTestCase;
import org.jetbrains.annotations.NotNull;
/**
@@ -37,6 +36,12 @@ public class MigrationTest extends MultiFileTestCase {
})));
}
public void testSameShortNameClass() throws Exception {
doTest(createAction(new MigrationMap(new MigrationMapEntry[]{
new MigrationMapEntry("aaa.Test", "bbb.Test", MigrationMapEntry.CLASS, false)
})));
}
public void testPackage() throws Exception {
doTest(createAction(new MigrationMap(new MigrationMapEntry[]{
new MigrationMapEntry("qqq", "java.lang", MigrationMapEntry.PACKAGE, true)