package jetbrains.mps.idea.java.refactoring;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiReference;
import com.intellij.psi.search.searches.MethodReferencesSearch;
import com.intellij.psi.search.searches.OverridingMethodsSearch;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.util.MergeQuery;
import com.intellij.util.Processor;
import com.intellij.util.Query;
import jetbrains.mps.findUsages.UsagesList;
import jetbrains.mps.ide.findusages.model.SearchResult;
import jetbrains.mps.ide.findusages.model.SearchResults;
import jetbrains.mps.ide.project.ProjectHelper;
import jetbrains.mps.idea.core.psi.impl.MPSPsiNode;
import jetbrains.mps.idea.core.psi.impl.MPSPsiNodeBase;
import jetbrains.mps.idea.core.psi.impl.MPSPsiProvider;
import jetbrains.mps.idea.core.refactoring.PsiRenameRefactoringWrapper;
import jetbrains.mps.idea.core.refactoring.PsiSearchResult;
import jetbrains.mps.idea.core.refactoring.RefactoringWrapper;
import jetbrains.mps.refactoring.framework.IRefactoring;
import jetbrains.mps.refactoring.framework.RefactoringContext;
import jetbrains.mps.refactoring.framework.RefactoringUtil;
import org.jetbrains.mps.openapi.model.SNode;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
/**
* danilla 6/4/13
*/
public class PsiMethodRenameRefactoringWrapper extends PsiRenameRefactoringWrapper {
public PsiMethodRenameRefactoringWrapper() {
super(RefactoringUtil.getRefactoringByClassName("jetbrains.mps.baseLanguage.refactorings.RenameMethod"));
}
@Override
public void refactor(RefactoringContext refactoringContext) {
// mps refactoring
baseRefactoring.refactor(refactoringContext);
// now do the PSI part of refactoring
Project project = ProjectHelper.toIdeaProject(refactoringContext.getSelectedProject());
PsiMethod method = (PsiMethod) MPSPsiProvider.getInstance(project).getPsi(refactoringContext.getSelectedNode());
String newName = (String) refactoringContext.getParameter("newName");
SearchResults<SNode> usages = (SearchResults<SNode>) refactoringContext.getUsages();
for (SearchResult<SNode> result : usages.getSearchResults()) {
if (!(result instanceof PsiSearchResult)) continue;
PsiReference psiRef = ((PsiSearchResult) result).getReference();
if (psiRef.getElement() instanceof MPSPsiNode) continue;
psiRef.handleElementRename(newName);
}
// rename overriding methods
for (PsiMethod m : OverridingMethodsSearch.search(method).findAll()) {
if (m instanceof MPSPsiNode) continue;
m.setName(newName);
}
}
@Override
public SearchResults getAffectedNodes(RefactoringContext refactoringContext) {
SearchResults<SNode> mpsResults = baseRefactoring.getAffectedNodes(refactoringContext);
Project project = ProjectHelper.toIdeaProject(refactoringContext.getSelectedProject());
PsiElement psiTarget = MPSPsiProvider.getInstance(project).getPsi(refactoringContext.getSelectedNode());
assert psiTarget instanceof PsiMethod;
PsiMethod method = (PsiMethod) psiTarget;
Query<PsiReference> query = query(method);
Collection<PsiReference> psiRefs = query.findAll();
// size may be bigger than needed, due to MPS usages returned among PSI usages
List<SearchResult<SNode>> psiResults = new ArrayList<SearchResult<SNode>>(psiRefs.size());
for (PsiReference ref : psiRefs) {
PsiElement element = ref.getElement();
if (element instanceof MPSPsiNode) continue;
psiResults.add(new PsiSearchResult(ref));
}
mpsResults.addAll(new SearchResults<SNode>(new HashSet<SNode>(), psiResults));
return mpsResults;
}
private Query<PsiReference> query(PsiMethod method) {
Query<PsiReference> exactUsages = MethodReferencesSearch.search(method);
// todo search scope?
// include overriding methods' usages
// todo fix this ugliness
final Query<PsiReference>[] query = new Query[]{exactUsages};
OverridingMethodsSearch.search(method).forEach(new Processor<PsiMethod>() {
@Override
public boolean process(PsiMethod psiMethod) {
Query<PsiReference> q = MethodReferencesSearch.search(psiMethod);
if (query[0] == null) {
query[0] = q;
} else {
query[0] = new MergeQuery<PsiReference>(query[0], q);
}
return false;
}
});
return query[0];
}
}