mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
replace duplicates when pull methods up
This commit is contained in:
@@ -1236,6 +1236,11 @@ public class ExtractMethodProcessor implements MatchProvider {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReplaceDuplicatesTitle(int idx, int size) {
|
||||
return RefactoringBundle.message("process.duplicates.title", idx, size);
|
||||
}
|
||||
|
||||
public InputVariables getInputVariables() {
|
||||
return myInputVariables;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
*/
|
||||
package com.intellij.refactoring.memberPullUp;
|
||||
|
||||
import com.intellij.analysis.AnalysisScope;
|
||||
import com.intellij.codeInsight.AnnotationUtil;
|
||||
import com.intellij.codeInsight.ChangeContextUtil;
|
||||
import com.intellij.codeInsight.PsiEquivalenceUtil;
|
||||
@@ -31,10 +32,12 @@ import com.intellij.codeInsight.intention.AddAnnotationFix;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettings;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
|
||||
import com.intellij.psi.search.LocalSearchScope;
|
||||
import com.intellij.psi.search.searches.ClassInheritorsSearch;
|
||||
import com.intellij.psi.search.searches.OverridingMethodsSearch;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.psi.util.*;
|
||||
@@ -48,10 +51,12 @@ import com.intellij.refactoring.util.RefactoringUIUtil;
|
||||
import com.intellij.refactoring.util.RefactoringUtil;
|
||||
import com.intellij.refactoring.util.classMembers.ClassMemberReferencesVisitor;
|
||||
import com.intellij.refactoring.util.classMembers.MemberInfo;
|
||||
import com.intellij.refactoring.util.duplicates.MethodDuplicatesHandler;
|
||||
import com.intellij.usageView.UsageInfo;
|
||||
import com.intellij.usageView.UsageViewDescriptor;
|
||||
import com.intellij.usageView.UsageViewUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.Query;
|
||||
import com.intellij.util.VisibilityUtil;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -94,6 +99,28 @@ public class PullUpHelper extends BaseRefactoringProcessor{
|
||||
protected void performRefactoring(UsageInfo[] usages) {
|
||||
moveMembersToBase();
|
||||
moveFieldInitializations();
|
||||
processMethodsDuplicates();
|
||||
}
|
||||
|
||||
private void processMethodsDuplicates() {
|
||||
final Query<PsiClass> search = ClassInheritorsSearch.search(myTargetSuperClass);
|
||||
final Set<VirtualFile> hierarchyFiles = new HashSet<VirtualFile>();
|
||||
for (PsiClass aClass : search) {
|
||||
final PsiFile containingFile = aClass.getContainingFile();
|
||||
if (containingFile != null) {
|
||||
final VirtualFile virtualFile = containingFile.getVirtualFile();
|
||||
if (virtualFile != null) {
|
||||
hierarchyFiles.add(virtualFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
final Set<PsiMethod> methodsToSearchDuplicates = new HashSet<PsiMethod>();
|
||||
for (PsiMember psiMember : myMembersAfterMove) {
|
||||
if (psiMember instanceof PsiMethod && ((PsiMethod)psiMember).getBody() != null) {
|
||||
methodsToSearchDuplicates.add((PsiMethod)psiMember);
|
||||
}
|
||||
}
|
||||
MethodDuplicatesHandler.invokeOnScope(myProject, methodsToSearchDuplicates, new AnalysisScope(myProject, hierarchyFiles), true);
|
||||
}
|
||||
|
||||
protected String getCommandName() {
|
||||
|
||||
@@ -107,7 +107,7 @@ public class DuplicatesImpl {
|
||||
if (!ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
if (showAll.get() == null || !showAll.get()) {
|
||||
final String prompt = provider.getConfirmDuplicatePrompt(match);
|
||||
final ReplacePromptDialog promptDialog = new ReplacePromptDialog(false, RefactoringBundle.message("process.duplicates.title", idx, size), project){
|
||||
final ReplacePromptDialog promptDialog = new ReplacePromptDialog(false, provider.getReplaceDuplicatesTitle(idx, size), project){
|
||||
@Override
|
||||
protected String getMessage() {
|
||||
final String message = super.getMessage();
|
||||
|
||||
@@ -33,4 +33,6 @@ public interface MatchProvider {
|
||||
boolean hasDuplicates();
|
||||
|
||||
@Nullable String getConfirmDuplicatePrompt(Match match);
|
||||
|
||||
String getReplaceDuplicatesTitle(int idx, int size);
|
||||
}
|
||||
|
||||
+67
-32
@@ -54,9 +54,7 @@ import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author dsl
|
||||
@@ -109,32 +107,60 @@ public class MethodDuplicatesHandler implements RefactoringActionHandler {
|
||||
}
|
||||
|
||||
public static void invokeOnScope(final Project project, final PsiMethod method, final AnalysisScope scope) {
|
||||
final List<Match> duplicates = new ArrayList<Match>();
|
||||
invokeOnScope(project, Collections.singleton(method), scope, false);
|
||||
}
|
||||
|
||||
public static void invokeOnScope(final Project project, final Set<PsiMethod> methods, final AnalysisScope scope, boolean silent) {
|
||||
final Map<PsiMethod, List<Match>> duplicates = new HashMap<PsiMethod, List<Match>>();
|
||||
scope.accept(new PsiRecursiveElementVisitor() {
|
||||
@Override public void visitFile(final PsiFile file) {
|
||||
final ProgressIndicator progressIndicator = ProgressManager.getInstance().getProgressIndicator();
|
||||
if (progressIndicator != null && progressIndicator.isCanceled()) return;
|
||||
duplicates.addAll(hasDuplicates(file, method));
|
||||
}
|
||||
});
|
||||
replaceDuplicate(project, duplicates, method);
|
||||
final Runnable nothingFoundRunnable = new Runnable() {
|
||||
public void run() {
|
||||
if (duplicates.isEmpty()) {
|
||||
final String message = RefactoringBundle.message("idea.has.not.found.any.code.that.can.be.replaced.with.method.call",
|
||||
ApplicationNamesInfo.getInstance().getProductName());
|
||||
Messages.showInfoMessage(project, message, REFACTORING_NAME);
|
||||
for (PsiMethod method : methods) {
|
||||
final List<Match> matchList = hasDuplicates(file, method);
|
||||
for (Iterator<Match> iterator = matchList.iterator(); iterator.hasNext(); ) {
|
||||
Match match = iterator.next();
|
||||
final PsiElement matchStart = match.getMatchStart();
|
||||
final PsiElement matchEnd = match.getMatchEnd();
|
||||
for (PsiMethod psiMethod : methods) {
|
||||
if (PsiTreeUtil.isAncestor(psiMethod, matchStart, false) ||
|
||||
PsiTreeUtil.isAncestor(psiMethod, matchEnd, false)) {
|
||||
iterator.remove();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!matchList.isEmpty()) {
|
||||
List<Match> matches = duplicates.get(method);
|
||||
if (matches == null) {
|
||||
matches = new ArrayList<Match>();
|
||||
duplicates.put(method, matches);
|
||||
}
|
||||
matches.addAll(matchList);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
nothingFoundRunnable.run();
|
||||
} else {
|
||||
ApplicationManager.getApplication().invokeLater(nothingFoundRunnable, ModalityState.NON_MODAL);
|
||||
});
|
||||
replaceDuplicate(project, duplicates, methods);
|
||||
if (!silent) {
|
||||
final Runnable nothingFoundRunnable = new Runnable() {
|
||||
public void run() {
|
||||
if (duplicates.isEmpty()) {
|
||||
final String message = RefactoringBundle.message("idea.has.not.found.any.code.that.can.be.replaced.with.method.call",
|
||||
ApplicationNamesInfo.getInstance().getProductName());
|
||||
Messages.showInfoMessage(project, message, REFACTORING_NAME);
|
||||
}
|
||||
}
|
||||
};
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
nothingFoundRunnable.run();
|
||||
} else {
|
||||
ApplicationManager.getApplication().invokeLater(nothingFoundRunnable, ModalityState.NON_MODAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void replaceDuplicate(final Project project, final List<Match> duplicates, final PsiMethod method) {
|
||||
private static void replaceDuplicate(final Project project, final Map<PsiMethod, List<Match>> duplicates, final Set<PsiMethod> methods) {
|
||||
LocalHistoryAction a = LocalHistory.getInstance().startAction(REFACTORING_NAME);
|
||||
try {
|
||||
final ProgressIndicator progressIndicator = ProgressManager.getInstance().getProgressIndicator();
|
||||
@@ -142,19 +168,23 @@ public class MethodDuplicatesHandler implements RefactoringActionHandler {
|
||||
|
||||
final Runnable replaceRunnable = new Runnable() {
|
||||
public void run() {
|
||||
final int duplicatesNo = duplicates.size();
|
||||
WindowManager.getInstance().getStatusBar(project).setInfo(getStatusMessage(duplicatesNo));
|
||||
CommandProcessor.getInstance().executeCommand(project, new Runnable() {
|
||||
public void run() {
|
||||
PostprocessReformattingAspect.getInstance(project).postponeFormattingInside(new Runnable() {
|
||||
public void run() {
|
||||
DuplicatesImpl.invoke(project, new MethodDuplicatesMatchProvider(method, duplicates));
|
||||
}
|
||||
});
|
||||
}
|
||||
}, REFACTORING_NAME, REFACTORING_NAME);
|
||||
for (final PsiMethod method : methods) {
|
||||
final List<Match> matches = duplicates.get(method);
|
||||
if (matches == null) continue;
|
||||
final int duplicatesNo = matches.size();
|
||||
WindowManager.getInstance().getStatusBar(project).setInfo(getStatusMessage(duplicatesNo));
|
||||
CommandProcessor.getInstance().executeCommand(project, new Runnable() {
|
||||
public void run() {
|
||||
PostprocessReformattingAspect.getInstance(project).postponeFormattingInside(new Runnable() {
|
||||
public void run() {
|
||||
DuplicatesImpl.invoke(project, new MethodDuplicatesMatchProvider(method, matches));
|
||||
}
|
||||
});
|
||||
}
|
||||
}, REFACTORING_NAME, REFACTORING_NAME);
|
||||
|
||||
WindowManager.getInstance().getStatusBar(project).setInfo("");
|
||||
WindowManager.getInstance().getStatusBar(project).setInfo("");
|
||||
}
|
||||
}
|
||||
};
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
@@ -348,5 +378,10 @@ public class MethodDuplicatesHandler implements RefactoringActionHandler {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReplaceDuplicatesTitle(int idx, int size) {
|
||||
return RefactoringBundle.message("process.methods.duplicates.title", idx, size, myMethod.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
class A {}
|
||||
class AImpl1 extends A{
|
||||
void f<caret>oo() {
|
||||
System.out.println("hello");
|
||||
System.out.println("hello");
|
||||
System.out.println("hello");
|
||||
System.out.println("hello");
|
||||
}
|
||||
}
|
||||
|
||||
class AImpl2 extends A {
|
||||
void bar() {
|
||||
System.out.println("hello");
|
||||
System.out.println("hello");
|
||||
System.out.println("hello");
|
||||
System.out.println("hello");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
class A {
|
||||
void foo() {
|
||||
System.out.println("hello");
|
||||
System.out.println("hello");
|
||||
System.out.println("hello");
|
||||
System.out.println("hello");
|
||||
}
|
||||
}
|
||||
class AImpl1 extends A{
|
||||
}
|
||||
|
||||
class AImpl2 extends A {
|
||||
void bar() {
|
||||
foo();
|
||||
}
|
||||
}
|
||||
@@ -94,6 +94,10 @@ public class PullUpTest extends LightCodeInsightTestCase {
|
||||
doTest(new RefactoringTestUtil.MemberDescriptor("method", PsiMethod.class, true));
|
||||
}
|
||||
|
||||
public void testReplaceDuplicatesInInheritors() throws Exception {
|
||||
doTest(new RefactoringTestUtil.MemberDescriptor("foo", PsiMethod.class, false));
|
||||
}
|
||||
|
||||
public void testGenericsInImplements() throws Exception {
|
||||
doTest(false, new RefactoringTestUtil.MemberDescriptor("I", PsiClass.class));
|
||||
}
|
||||
|
||||
@@ -623,6 +623,7 @@ replace.this.code.fragment.and.make.method.static.visible= (Method will be made
|
||||
replace.this.code.fragment.and.make.method.visible= (Method will be made {0})
|
||||
replace.this.code.fragment.and.change.signature=\nMethod signature will be changed to \n{0}
|
||||
process.duplicates.title=Process Duplicate {0} of {1}
|
||||
process.methods.duplicates.title=Process Method {2} Duplicate ({0} of {1})
|
||||
0.has.detected.1.code.fragments.in.this.file.that.can.be.replaced.with.a.call.to.extracted.method={0} has detected {1} code fragments in this file that can be replaced with a call to extracted method. Would you like to review and replace them?
|
||||
replace.button=Replace
|
||||
method.duplicates.method.label=Method {0}
|
||||
|
||||
Reference in New Issue
Block a user