mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -1,99 +0,0 @@
|
||||
package com.jetbrains.python.refactoring.extractmethod;
|
||||
|
||||
import com.intellij.codeInsight.PsiEquivalenceUtil;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.PsiComment;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiWhiteSpace;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.jetbrains.python.psi.PyFunction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* User : ktisha
|
||||
*/
|
||||
public class PyDuplicatesFinder {
|
||||
private final ArrayList<PsiElement> myPattern;
|
||||
|
||||
public PyDuplicatesFinder(@NotNull final PsiElement statement1, @NotNull final PsiElement statement2) {
|
||||
myPattern = new ArrayList<PsiElement>();
|
||||
PsiElement sibling = statement1;
|
||||
|
||||
do {
|
||||
myPattern.add(sibling);
|
||||
if (sibling == statement2) break;
|
||||
sibling = PsiTreeUtil.skipSiblingsForward(sibling, PsiWhiteSpace.class, PsiComment.class);
|
||||
} while (sibling != null);
|
||||
}
|
||||
|
||||
public List<Pair<PsiElement, PsiElement>> findDuplicates(@Nullable final List<PsiElement> scope, @NotNull final PyFunction generatedMethod) {
|
||||
final ArrayList<Pair<PsiElement, PsiElement>> result = new ArrayList<Pair<PsiElement, PsiElement>>();
|
||||
if (scope != null) {
|
||||
for (PsiElement element : scope) {
|
||||
findPatternOccurrences(result, element, generatedMethod);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private void findPatternOccurrences(@NotNull final List<Pair<PsiElement, PsiElement>> array, @NotNull final PsiElement scope,
|
||||
@NotNull final PyFunction generatedMethod) {
|
||||
if (scope == generatedMethod) return;
|
||||
final PsiElement[] children = scope.getChildren();
|
||||
for (PsiElement child : children) {
|
||||
final Pair<PsiElement, PsiElement> match = isDuplicateFragment(child);
|
||||
if (match != null) {
|
||||
array.add(match);
|
||||
continue;
|
||||
}
|
||||
findPatternOccurrences(array, child, generatedMethod);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Pair<PsiElement, PsiElement> isDuplicateFragment(@NotNull final PsiElement candidate) {
|
||||
for (PsiElement pattern : myPattern) {
|
||||
if (PsiTreeUtil.isAncestor(pattern, candidate, false)) return null;
|
||||
}
|
||||
PsiElement sibling = candidate;
|
||||
final ArrayList<PsiElement> candidates = new ArrayList<PsiElement>();
|
||||
for (int i = 0; i != myPattern.size(); ++i) {
|
||||
if (sibling == null) return null;
|
||||
|
||||
candidates.add(sibling);
|
||||
sibling = PsiTreeUtil.skipSiblingsForward(sibling, PsiWhiteSpace.class, PsiComment.class);
|
||||
}
|
||||
if (myPattern.size() != candidates.size()) return null;
|
||||
if (candidates.size() <= 0) return null;
|
||||
final Pair<PsiElement, PsiElement> match = new Pair<PsiElement, PsiElement>(candidates.get(0), candidates.get(candidates.size() - 1));
|
||||
for (int i = 0; i < myPattern.size(); i++) {
|
||||
if (!matchPattern(myPattern.get(i), candidates.get(i))) return null;
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
private static boolean matchPattern(@Nullable final PsiElement pattern,
|
||||
@Nullable final PsiElement candidate) {
|
||||
if (pattern == null || candidate == null) return pattern == candidate;
|
||||
final PsiElement[] children1 = PsiEquivalenceUtil.getFilteredChildren(pattern, null, true);
|
||||
final PsiElement[] children2 = PsiEquivalenceUtil.getFilteredChildren(candidate, null, true);
|
||||
if (children1.length != children2.length) return false;
|
||||
|
||||
for (int i = 0; i < children1.length; i++) {
|
||||
PsiElement child1 = children1[i];
|
||||
PsiElement child2 = children2[i];
|
||||
if (!matchPattern(child1, child2)) return false;
|
||||
}
|
||||
|
||||
if (children1.length == 0) {
|
||||
if (!pattern.textMatches(candidate)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
+20
-68
@@ -2,21 +2,12 @@ package com.jetbrains.python.refactoring.extractmethod;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightUtilCore;
|
||||
import com.intellij.codeInsight.codeFragment.CodeFragment;
|
||||
import com.intellij.codeInsight.highlighting.HighlightManager;
|
||||
import com.intellij.find.FindManager;
|
||||
import com.intellij.lang.LanguageNamesValidation;
|
||||
import com.intellij.lang.refactoring.NamesValidator;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.application.ApplicationNamesInfo;
|
||||
import com.intellij.openapi.command.CommandProcessor;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.LogicalPosition;
|
||||
import com.intellij.openapi.editor.ScrollType;
|
||||
import com.intellij.openapi.editor.colors.EditorColors;
|
||||
import com.intellij.openapi.editor.colors.EditorColorsManager;
|
||||
import com.intellij.openapi.editor.markup.TextAttributes;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
@@ -26,20 +17,18 @@ import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import com.intellij.psi.impl.source.codeStyle.CodeEditUtil;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.refactoring.RefactoringBundle;
|
||||
import com.intellij.refactoring.extractMethod.AbstractExtractMethodDialog;
|
||||
import com.intellij.refactoring.extractMethod.AbstractVariableData;
|
||||
import com.intellij.refactoring.extractMethod.ExtractMethodDecorator;
|
||||
import com.intellij.refactoring.extractMethod.ExtractMethodValidator;
|
||||
import com.intellij.refactoring.extractMethod.*;
|
||||
import com.intellij.refactoring.listeners.RefactoringElementListenerComposite;
|
||||
import com.intellij.refactoring.rename.RenameUtil;
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil;
|
||||
import com.intellij.ui.ReplacePromptDialog;
|
||||
import com.intellij.usageView.UsageInfo;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.containers.hash.HashMap;
|
||||
import com.jetbrains.python.PyBundle;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.PythonFileType;
|
||||
import com.jetbrains.python.PythonLanguage;
|
||||
import com.jetbrains.python.codeInsight.codeFragment.PyCodeFragment;
|
||||
import com.jetbrains.python.codeInsight.controlflow.ControlFlowCache;
|
||||
@@ -98,7 +87,7 @@ public class PyExtractMethodUtil {
|
||||
final String methodName = data.first;
|
||||
final AbstractVariableData[] variableData = data.second;
|
||||
|
||||
final PyDuplicatesFinder finder = new PyDuplicatesFinder(statement1, statement2);
|
||||
final SimpleDuplicatesFinder finder = new SimpleDuplicatesFinder(statement1, statement2);
|
||||
|
||||
if (fragment.getOutputVariables().isEmpty()) {
|
||||
CommandProcessor.getInstance().executeCommand(project, new Runnable() {
|
||||
@@ -200,7 +189,7 @@ public class PyExtractMethodUtil {
|
||||
|
||||
private static void processDuplicates(@NotNull final PsiElement callElement,
|
||||
@NotNull final PyFunction generatedMethod,
|
||||
@NotNull final PyDuplicatesFinder finder,
|
||||
@NotNull final SimpleDuplicatesFinder finder,
|
||||
@NotNull final Editor editor) {
|
||||
ScopeOwner owner = ScopeUtil.getScopeOwner(callElement);
|
||||
if (owner instanceof PsiFile) return;
|
||||
@@ -215,57 +204,19 @@ public class PyExtractMethodUtil {
|
||||
}
|
||||
}
|
||||
}
|
||||
final List<Pair<PsiElement, PsiElement>> duplicates = finder.findDuplicates(scope, generatedMethod);
|
||||
|
||||
if (duplicates.size() > 0) {
|
||||
final String message = RefactoringBundle.message("0.has.detected.1.code.fragments.in.this.file.that.can.be.replaced.with.a.call.to.extracted.method",
|
||||
ApplicationNamesInfo.getInstance().getProductName(), duplicates.size());
|
||||
final boolean isUnittest = ApplicationManager.getApplication().isUnitTestMode();
|
||||
final int exitCode = !isUnittest ? Messages.showYesNoDialog(callElement.getProject(), message,
|
||||
RefactoringBundle.message("refactoring.extract.method.dialog.title"), Messages.getInformationIcon()) :
|
||||
DialogWrapper.OK_EXIT_CODE;
|
||||
if (exitCode == DialogWrapper.OK_EXIT_CODE) {
|
||||
boolean replaceAll = false;
|
||||
for (Pair<PsiElement, PsiElement> match : duplicates) {
|
||||
final List<PsiElement> elementsRange = PyPsiUtils.collectElements(match.getFirst(), match.getSecond());
|
||||
if (!replaceAll) {
|
||||
highlightInEditor(callElement.getProject(), match, editor);
|
||||
|
||||
int promptResult = FindManager.PromptResult.ALL;
|
||||
if (!isUnittest) {
|
||||
ReplacePromptDialog promptDialog = new ReplacePromptDialog(false, RefactoringBundle.message("replace.fragment"), callElement.getProject());
|
||||
promptDialog.show();
|
||||
promptResult = promptDialog.getExitCode();
|
||||
}
|
||||
if (promptResult == FindManager.PromptResult.SKIP) continue;
|
||||
if (promptResult == FindManager.PromptResult.CANCEL) break;
|
||||
|
||||
if (promptResult == FindManager.PromptResult.OK) {
|
||||
replaceElements(elementsRange, callElement);
|
||||
}
|
||||
else if (promptResult == FindManager.PromptResult.ALL) {
|
||||
replaceElements(elementsRange, callElement);
|
||||
replaceAll = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
replaceElements(elementsRange, callElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void highlightInEditor(@NotNull final Project project, @NotNull final Pair<PsiElement, PsiElement> pair,
|
||||
@NotNull final Editor editor) {
|
||||
final HighlightManager highlightManager = HighlightManager.getInstance(project);
|
||||
final EditorColorsManager colorsManager = EditorColorsManager.getInstance();
|
||||
final TextAttributes attributes = colorsManager.getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES);
|
||||
final int startOffset = pair.getFirst().getTextRange().getStartOffset();
|
||||
final int endOffset = pair.getSecond().getTextRange().getEndOffset();
|
||||
highlightManager.addRangeHighlight(editor, startOffset, endOffset, attributes, true, null);
|
||||
final LogicalPosition logicalPosition = editor.offsetToLogicalPosition(startOffset);
|
||||
editor.getScrollingModel().scrollTo(logicalPosition, ScrollType.MAKE_VISIBLE);
|
||||
ExtractMethodHelper.processDuplicates(callElement, generatedMethod, scope, finder, editor,
|
||||
new Function<Pair<PsiElement, PsiElement>, List<PsiElement>>() {
|
||||
@Override
|
||||
public List<PsiElement> fun(Pair<PsiElement, PsiElement> pair) {
|
||||
return PyPsiUtils.collectElements(pair.first, pair.second);
|
||||
}
|
||||
},
|
||||
new Consumer<Pair<List<PsiElement>, PsiElement>>() {
|
||||
@Override
|
||||
public void consume(Pair<List<PsiElement>, PsiElement> pair) {
|
||||
replaceElements(pair.first, pair.second);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void processGlobalWrites(@NotNull final PyFunction function, @NotNull final PyCodeFragment fragment) {
|
||||
@@ -637,7 +588,8 @@ public class PyExtractMethodUtil {
|
||||
}
|
||||
};
|
||||
|
||||
final AbstractExtractMethodDialog dialog = new AbstractExtractMethodDialog(project, "method_name", fragment, validator, decorator) {
|
||||
final AbstractExtractMethodDialog dialog = new AbstractExtractMethodDialog(project, "method_name", fragment, validator, decorator,
|
||||
PythonFileType.INSTANCE) {
|
||||
@Override
|
||||
protected String getHelpId() {
|
||||
return "python.reference.extractMethod";
|
||||
|
||||
Reference in New Issue
Block a user