2 * Copyright 2000-2016 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.intellij.refactoring.extractMethod;
18 import com.intellij.codeInsight.ChangeContextUtil;
19 import com.intellij.codeInsight.CodeInsightUtil;
20 import com.intellij.codeInsight.ExceptionUtil;
21 import com.intellij.codeInsight.NullableNotNullManager;
22 import com.intellij.codeInsight.daemon.impl.analysis.JavaHighlightUtil;
23 import com.intellij.codeInsight.daemon.impl.quickfix.AnonymousTargetClassPreselectionUtil;
24 import com.intellij.codeInsight.generation.GenerateMembersUtil;
25 import com.intellij.codeInsight.highlighting.HighlightManager;
26 import com.intellij.codeInsight.intention.impl.AddNullableNotNullAnnotationFix;
27 import com.intellij.codeInsight.navigation.NavigationUtil;
28 import com.intellij.codeInspection.dataFlow.*;
29 import com.intellij.codeInspection.dataFlow.instructions.BranchingInstruction;
30 import com.intellij.codeInspection.dataFlow.instructions.Instruction;
31 import com.intellij.ide.DataManager;
32 import com.intellij.ide.util.PropertiesComponent;
33 import com.intellij.ide.util.PsiClassListCellRenderer;
34 import com.intellij.openapi.application.ApplicationManager;
35 import com.intellij.openapi.diagnostic.Logger;
36 import com.intellij.openapi.editor.Editor;
37 import com.intellij.openapi.editor.LogicalPosition;
38 import com.intellij.openapi.editor.ScrollType;
39 import com.intellij.openapi.editor.colors.EditorColors;
40 import com.intellij.openapi.editor.colors.EditorColorsManager;
41 import com.intellij.openapi.editor.markup.TextAttributes;
42 import com.intellij.openapi.progress.ProgressManager;
43 import com.intellij.openapi.project.Project;
44 import com.intellij.openapi.util.*;
45 import com.intellij.openapi.util.text.StringUtil;
46 import com.intellij.openapi.vfs.VirtualFile;
47 import com.intellij.openapi.wm.WindowManager;
48 import com.intellij.psi.*;
49 import com.intellij.psi.codeStyle.*;
50 import com.intellij.psi.controlFlow.ControlFlowUtil;
51 import com.intellij.psi.impl.source.codeStyle.JavaCodeStyleManagerImpl;
52 import com.intellij.psi.scope.processor.VariablesProcessor;
53 import com.intellij.psi.scope.util.PsiScopesUtil;
54 import com.intellij.psi.search.GlobalSearchScope;
55 import com.intellij.psi.search.LocalSearchScope;
56 import com.intellij.psi.search.PsiElementProcessor;
57 import com.intellij.psi.search.SearchScope;
58 import com.intellij.psi.search.searches.ReferencesSearch;
59 import com.intellij.psi.tree.IElementType;
60 import com.intellij.psi.util.*;
61 import com.intellij.refactoring.HelpID;
62 import com.intellij.refactoring.RefactoringBundle;
63 import com.intellij.refactoring.extractMethodObject.ExtractMethodObjectHandler;
64 import com.intellij.refactoring.introduceField.ElementToWorkOn;
65 import com.intellij.refactoring.introduceVariable.IntroduceVariableBase;
66 import com.intellij.refactoring.util.*;
67 import com.intellij.refactoring.util.classMembers.ElementNeedsThis;
68 import com.intellij.refactoring.util.duplicates.*;
69 import com.intellij.util.*;
70 import com.intellij.util.containers.ContainerUtil;
71 import com.intellij.util.containers.MultiMap;
72 import org.jetbrains.annotations.NonNls;
73 import org.jetbrains.annotations.NotNull;
74 import org.jetbrains.annotations.Nullable;
75 import org.jetbrains.annotations.TestOnly;
79 public class ExtractMethodProcessor implements MatchProvider {
80 private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.extractMethod.ExtractMethodProcessor");
82 protected final Project myProject;
83 private final Editor myEditor;
84 protected final PsiElement[] myElements;
85 private final PsiBlockStatement myEnclosingBlockStatement;
86 private final PsiType myForcedReturnType;
87 private final String myRefactoringName;
88 protected final String myInitialMethodName;
89 private final String myHelpId;
91 private final PsiManager myManager;
92 private final PsiElementFactory myElementFactory;
93 private final CodeStyleManager myStyleManager;
95 private PsiExpression myExpression;
97 private PsiElement myCodeFragmentMember; // parent of myCodeFragment
99 protected String myMethodName; // name for extracted method
100 protected PsiType myReturnType; // return type for extracted method
101 protected PsiTypeParameterList myTypeParameterList; //type parameter list of extracted method
102 private VariableData[] myVariableDatum; // parameter data for extracted method
103 protected PsiClassType[] myThrownExceptions; // exception to declare as thrown by extracted method
104 protected boolean myStatic; // whether to declare extracted method static
106 protected PsiClass myTargetClass; // class to create the extracted method in
107 private PsiElement myAnchor; // anchor to insert extracted method after it
109 protected ControlFlowWrapper myControlFlowWrapper;
110 protected InputVariables myInputVariables; // input variables
111 protected PsiVariable[] myOutputVariables; // output variables
112 protected PsiVariable myOutputVariable; // the only output variable
113 private PsiVariable myArtificialOutputVariable;
114 private Collection<PsiStatement> myExitStatements;
116 private boolean myHasReturnStatement; // there is a return statement
117 private boolean myHasReturnStatementOutput; // there is a return statement and its type is not void
118 protected boolean myHasExpressionOutput; // extracted code is an expression with non-void type
119 private boolean myNeedChangeContext; // target class is not immediate container of the code to be extracted
121 private boolean myShowErrorDialogs = true;
122 protected boolean myCanBeStatic;
123 protected boolean myCanBeChainedConstructor;
124 protected boolean myIsChainedConstructor;
125 private List<Match> myDuplicates;
126 @PsiModifier.ModifierConstant private String myMethodVisibility = PsiModifier.PRIVATE;
127 protected boolean myGenerateConditionalExit;
128 protected PsiStatement myFirstExitStatementCopy;
129 private PsiMethod myExtractedMethod;
130 private PsiMethodCallExpression myMethodCall;
131 protected boolean myNullConditionalCheck;
132 protected boolean myNotNullConditionalCheck;
133 private Nullness myNullness;
135 public ExtractMethodProcessor(Project project,
137 PsiElement[] elements,
138 PsiType forcedReturnType,
139 String refactoringName,
140 String initialMethodName,
144 if (elements.length != 1 || !(elements[0] instanceof PsiBlockStatement)) {
145 myElements = elements.length == 1 && elements[0] instanceof PsiParenthesizedExpression
146 ? new PsiElement[] {PsiUtil.skipParenthesizedExprDown((PsiExpression)elements[0])} : elements;
147 myEnclosingBlockStatement = null;
150 myEnclosingBlockStatement = (PsiBlockStatement)elements[0];
151 PsiElement[] codeBlockChildren = myEnclosingBlockStatement.getCodeBlock().getChildren();
152 myElements = processCodeBlockChildren(codeBlockChildren);
154 myForcedReturnType = forcedReturnType;
155 myRefactoringName = refactoringName;
156 myInitialMethodName = initialMethodName;
159 myManager = PsiManager.getInstance(myProject);
160 myElementFactory = JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory();
161 myStyleManager = CodeStyleManager.getInstance(myProject);
164 private static PsiElement[] processCodeBlockChildren(PsiElement[] codeBlockChildren) {
165 int resultLast = codeBlockChildren.length;
167 if (codeBlockChildren.length == 0) return PsiElement.EMPTY_ARRAY;
169 final PsiElement first = codeBlockChildren[0];
171 if (first instanceof PsiJavaToken && ((PsiJavaToken)first).getTokenType() == JavaTokenType.LBRACE) {
174 final PsiElement last = codeBlockChildren[codeBlockChildren.length - 1];
175 if (last instanceof PsiJavaToken && ((PsiJavaToken)last).getTokenType() == JavaTokenType.RBRACE) {
178 final ArrayList<PsiElement> result = new ArrayList<PsiElement>();
179 for (int i = resultStart; i < resultLast; i++) {
180 PsiElement element = codeBlockChildren[i];
181 if (!(element instanceof PsiWhiteSpace)) {
186 return PsiUtilCore.toPsiElementArray(result);
190 * Method for test purposes
192 public void setShowErrorDialogs(boolean showErrorDialogs) {
193 myShowErrorDialogs = showErrorDialogs;
196 public void setChainedConstructor(final boolean isChainedConstructor) {
197 myIsChainedConstructor = isChainedConstructor;
201 public boolean prepare() throws PrepareFailedException {
202 return prepare(null);
206 * Invoked in atomic action
208 public boolean prepare(@Nullable Pass<ExtractMethodProcessor> pass) throws PrepareFailedException {
210 if (myElements.length == 1 && myElements[0] instanceof PsiExpression) {
211 final PsiExpression expression = (PsiExpression)myElements[0];
212 if (expression instanceof PsiAssignmentExpression && expression.getParent() instanceof PsiExpressionStatement) {
213 myElements[0] = expression.getParent();
216 myExpression = expression;
220 final PsiElement codeFragment = ControlFlowUtil.findCodeFragment(myElements[0]);
221 myCodeFragmentMember = codeFragment.getUserData(ElementToWorkOn.PARENT);
222 if (myCodeFragmentMember == null) {
223 myCodeFragmentMember = codeFragment.getParent();
225 if (myCodeFragmentMember == null) {
226 myCodeFragmentMember = ControlFlowUtil.findCodeFragment(codeFragment.getContext()).getParent();
229 myControlFlowWrapper = new ControlFlowWrapper(myProject, codeFragment, myElements);
232 myExitStatements = myControlFlowWrapper.prepareExitStatements(myElements);
233 if (myControlFlowWrapper.isGenerateConditionalExit()) {
234 myGenerateConditionalExit = true;
236 myHasReturnStatement = myExpression == null && myControlFlowWrapper.isReturnPresentBetween();
238 myFirstExitStatementCopy = myControlFlowWrapper.getFirstExitStatementCopy();
240 catch (ControlFlowWrapper.ExitStatementsNotSameException e) {
241 myExitStatements = myControlFlowWrapper.getExitStatements();
242 myNotNullConditionalCheck = areAllExitPointsAreNotNull(getExpectedReturnType());
243 if (!myNotNullConditionalCheck) {
244 showMultipleExitPointsMessage();
249 myOutputVariables = myControlFlowWrapper.getOutputVariables();
251 return chooseTargetClass(codeFragment, pass);
254 private boolean checkExitPoints() throws PrepareFailedException {
255 PsiType expressionType = null;
256 if (myExpression != null) {
257 if (myForcedReturnType != null) {
258 expressionType = myForcedReturnType;
261 expressionType = RefactoringUtil.getTypeByExpressionWithExpectedType(myExpression);
262 if (expressionType == null && !(myExpression.getParent() instanceof PsiExpressionStatement)) {
263 expressionType = PsiType.getJavaLangObject(myExpression.getManager(), GlobalSearchScope.allScope(myProject));
267 if (expressionType == null) {
268 expressionType = PsiType.VOID;
270 myHasExpressionOutput = !PsiType.VOID.equals(expressionType);
272 final PsiType returnStatementType = getExpectedReturnType();
273 myHasReturnStatementOutput = myHasReturnStatement && returnStatementType != null && !PsiType.VOID.equals(returnStatementType);
275 if (myGenerateConditionalExit && myOutputVariables.length == 1) {
276 if (!(myOutputVariables[0].getType() instanceof PsiPrimitiveType)) {
277 myNullConditionalCheck = true;
278 for (PsiStatement exitStatement : myExitStatements) {
279 if (exitStatement instanceof PsiReturnStatement) {
280 final PsiExpression returnValue = ((PsiReturnStatement)exitStatement).getReturnValue();
281 myNullConditionalCheck &= returnValue == null || isNullInferred(returnValue.getText(), true);
284 myNullConditionalCheck &= isNullInferred(myOutputVariables[0].getName(), false);
287 myNotNullConditionalCheck = areAllExitPointsAreNotNull(returnStatementType);
290 if (!myHasReturnStatementOutput && checkOutputVariablesCount() && !myNullConditionalCheck && !myNotNullConditionalCheck) {
291 showMultipleOutputMessage(expressionType);
295 myOutputVariable = myOutputVariables.length > 0 ? myOutputVariables[0] : null;
296 if (myNotNullConditionalCheck) {
297 myReturnType = returnStatementType instanceof PsiPrimitiveType ? ((PsiPrimitiveType)returnStatementType).getBoxedType(myCodeFragmentMember)
298 : returnStatementType;
299 } else if (myHasReturnStatementOutput) {
300 myReturnType = returnStatementType;
302 else if (myOutputVariable != null) {
303 myReturnType = myOutputVariable.getType();
305 else if (myGenerateConditionalExit) {
306 myReturnType = PsiType.BOOLEAN;
309 myReturnType = expressionType;
312 PsiElement container = PsiTreeUtil.getParentOfType(myElements[0], PsiClass.class, PsiMethod.class);
313 while (container instanceof PsiMethod && ((PsiMethod)container).getContainingClass() != myTargetClass) {
314 container = PsiTreeUtil.getParentOfType(container, PsiMethod.class, true);
316 if (container instanceof PsiMethod) {
317 PsiElement[] elements = myElements;
318 if (myExpression == null) {
319 if (myOutputVariable != null) {
320 elements = ArrayUtil.append(myElements, myOutputVariable, PsiElement.class);
322 if (myCodeFragmentMember instanceof PsiMethod && myReturnType == ((PsiMethod)myCodeFragmentMember).getReturnType()) {
323 elements = ArrayUtil.append(myElements, ((PsiMethod)myCodeFragmentMember).getReturnTypeElement(), PsiElement.class);
326 myTypeParameterList = RefactoringUtil.createTypeParameterListWithUsedTypeParameters(((PsiMethod)container).getTypeParameterList(),
329 List<PsiClassType> exceptions = ExceptionUtil.getThrownCheckedExceptions(myElements);
330 myThrownExceptions = exceptions.toArray(new PsiClassType[exceptions.size()]);
332 if (container instanceof PsiMethod) {
333 checkLocalClasses((PsiMethod) container);
338 private PsiType getExpectedReturnType() {
339 return myCodeFragmentMember instanceof PsiMethod
340 ? ((PsiMethod)myCodeFragmentMember).getReturnType()
341 : myCodeFragmentMember instanceof PsiLambdaExpression
342 ? LambdaUtil.getFunctionalInterfaceReturnType((PsiLambdaExpression)myCodeFragmentMember)
347 private PsiVariable getArtificialOutputVariable() {
348 if (myOutputVariables.length == 0 && myExitStatements.isEmpty()) {
349 if (myCanBeChainedConstructor) {
350 final Set<PsiField> fields = new HashSet<PsiField>();
351 for (PsiElement element : myElements) {
352 element.accept(new JavaRecursiveElementWalkingVisitor() {
354 public void visitReferenceExpression(PsiReferenceExpression expression) {
355 super.visitReferenceExpression(expression);
356 final PsiElement resolve = expression.resolve();
357 if (resolve instanceof PsiField && ((PsiField)resolve).hasModifierProperty(PsiModifier.FINAL) &&
358 PsiUtil.isAccessedForWriting(expression)) {
359 fields.add((PsiField)resolve);
364 if (!fields.isEmpty()) {
365 return fields.size() == 1 ? fields.iterator().next() : null;
368 final VariablesProcessor processor = new VariablesProcessor(true) {
370 protected boolean check(PsiVariable var, ResolveState state) {
371 return isDeclaredInside(var);
374 PsiScopesUtil.treeWalkUp(processor, myElements[myElements.length - 1], myCodeFragmentMember);
375 if (processor.size() == 1) {
376 return processor.getResult(0);
382 private boolean areAllExitPointsAreNotNull(PsiType returnStatementType) {
383 if (insertNotNullCheckIfPossible() && myControlFlowWrapper.getOutputVariables(false).length == 0) {
384 boolean isNotNull = returnStatementType != null && !PsiType.VOID.equals(returnStatementType);
385 for (PsiStatement statement : myExitStatements) {
386 if (statement instanceof PsiReturnStatement) {
387 final PsiExpression returnValue = ((PsiReturnStatement)statement).getReturnValue();
388 isNotNull &= returnValue != null && !isNullInferred(returnValue.getText(), true);
396 protected boolean insertNotNullCheckIfPossible() {
400 private boolean isNullInferred(String exprText, boolean trueSet) {
401 final PsiCodeBlock block = myElementFactory.createCodeBlockFromText("{}", myElements[0]);
402 for (PsiElement element : myElements) {
405 final PsiIfStatement statementFromText = (PsiIfStatement)myElementFactory.createStatementFromText("if (" + exprText + " == null);", null);
406 block.add(statementFromText);
408 final StandardDataFlowRunner dfaRunner = new StandardDataFlowRunner();
409 final StandardInstructionVisitor visitor = new StandardInstructionVisitor();
410 final RunnerResult rc = dfaRunner.analyzeMethod(block, visitor);
411 if (rc == RunnerResult.OK) {
412 final Pair<Set<Instruction>, Set<Instruction>> expressions = dfaRunner.getConstConditionalExpressions();
413 final Set<Instruction> set = trueSet ? expressions.getFirst() : expressions.getSecond();
414 for (Instruction instruction : set) {
415 if (instruction instanceof BranchingInstruction) {
416 if (((BranchingInstruction)instruction).getPsiAnchor().getText().equals(statementFromText.getCondition().getText())) {
425 protected boolean checkOutputVariablesCount() {
426 int outputCount = (myHasExpressionOutput ? 1 : 0) + (myGenerateConditionalExit ? 1 : 0) + myOutputVariables.length;
427 return outputCount > 1;
430 private void checkCanBeChainedConstructor() {
431 if (!(myCodeFragmentMember instanceof PsiMethod)) {
434 final PsiMethod method = (PsiMethod)myCodeFragmentMember;
435 if (!method.isConstructor() || !PsiType.VOID.equals(myReturnType)) {
438 final PsiCodeBlock body = method.getBody();
439 if (body == null) return;
440 final PsiStatement[] psiStatements = body.getStatements();
441 if (psiStatements.length > 0 && myElements [0] == psiStatements [0]) {
442 myCanBeChainedConstructor = true;
446 private void checkLocalClasses(final PsiMethod container) throws PrepareFailedException {
447 final List<PsiClass> localClasses = new ArrayList<PsiClass>();
448 container.accept(new JavaRecursiveElementWalkingVisitor() {
449 @Override public void visitClass(final PsiClass aClass) {
450 localClasses.add(aClass);
453 @Override public void visitAnonymousClass(final PsiAnonymousClass aClass) {
454 visitElement(aClass);
457 @Override public void visitTypeParameter(final PsiTypeParameter classParameter) {
458 visitElement(classParameter);
461 for(PsiClass localClass: localClasses) {
462 final boolean classExtracted = isExtractedElement(localClass);
463 final List<PsiElement> extractedReferences = Collections.synchronizedList(new ArrayList<PsiElement>());
464 final List<PsiElement> remainingReferences = Collections.synchronizedList(new ArrayList<PsiElement>());
465 ReferencesSearch.search(localClass).forEach(new Processor<PsiReference>() {
466 public boolean process(final PsiReference psiReference) {
467 final PsiElement element = psiReference.getElement();
468 final boolean elementExtracted = isExtractedElement(element);
469 if (elementExtracted && !classExtracted) {
470 extractedReferences.add(element);
473 if (!elementExtracted && classExtracted) {
474 remainingReferences.add(element);
480 if (!extractedReferences.isEmpty()) {
481 throw new PrepareFailedException("Cannot extract method because the selected code fragment uses local classes defined outside of the fragment", extractedReferences.get(0));
483 if (!remainingReferences.isEmpty()) {
484 throw new PrepareFailedException("Cannot extract method because the selected code fragment defines local classes used outside of the fragment", remainingReferences.get(0));
486 if (classExtracted) {
487 for (PsiVariable variable : myControlFlowWrapper.getUsedVariables()) {
488 if (isDeclaredInside(variable) && !variable.equals(myOutputVariable) && PsiUtil.resolveClassInType(variable.getType()) == localClass) {
489 throw new PrepareFailedException("Cannot extract method because the selected code fragment defines variable of local class type used outside of the fragment", variable);
496 private boolean isExtractedElement(final PsiElement element) {
497 boolean isExtracted = false;
498 for(PsiElement psiElement: myElements) {
499 if (PsiTreeUtil.isAncestor(psiElement, element, false)) {
509 private boolean shouldBeStatic() {
510 for(PsiElement element: myElements) {
511 final PsiExpressionStatement statement = PsiTreeUtil.getParentOfType(element, PsiExpressionStatement.class);
512 if (statement != null && JavaHighlightUtil.isSuperOrThisCall(statement, true, true)) {
516 PsiElement codeFragmentMember = myCodeFragmentMember;
517 while (codeFragmentMember != null && PsiTreeUtil.isAncestor(myTargetClass, codeFragmentMember, true)) {
518 if (codeFragmentMember instanceof PsiModifierListOwner && ((PsiModifierListOwner)codeFragmentMember).hasModifierProperty(PsiModifier.STATIC)) {
521 codeFragmentMember = PsiTreeUtil.getParentOfType(codeFragmentMember, PsiModifierListOwner.class, true);
526 public boolean showDialog(final boolean direct) {
527 AbstractExtractDialog dialog = createExtractMethodDialog(direct);
529 if (!dialog.isOK()) return false;
534 protected void apply(final AbstractExtractDialog dialog) {
535 myMethodName = dialog.getChosenMethodName();
536 myVariableDatum = dialog.getChosenParameters();
537 myStatic = isStatic() | dialog.isMakeStatic();
538 myIsChainedConstructor = dialog.isChainedConstructor();
539 myMethodVisibility = dialog.getVisibility();
541 final PsiType returnType = dialog.getReturnType();
542 if (returnType != null) {
543 myReturnType = returnType;
547 protected AbstractExtractDialog createExtractMethodDialog(final boolean direct) {
548 final List<VariableData> variables = myInputVariables.getInputVariables();
549 myVariableDatum = variables.toArray(new VariableData[variables.size()]);
550 myNullness = initNullness();
551 myArtificialOutputVariable = PsiType.VOID.equals(myReturnType) ? getArtificialOutputVariable() : null;
552 final PsiType returnType = myArtificialOutputVariable != null ? myArtificialOutputVariable.getType() : myReturnType;
553 return new ExtractMethodDialog(myProject, myTargetClass, myInputVariables, returnType, getTypeParameterList(),
554 getThrownExceptions(), isStatic(), isCanBeStatic(), myCanBeChainedConstructor,
555 myRefactoringName, myHelpId, myNullness, myElements) {
556 protected boolean areTypesDirected() {
561 protected String[] suggestMethodNames() {
562 return suggestInitialMethodName();
566 protected PsiExpression[] findOccurrences() {
567 return ExtractMethodProcessor.this.findOccurrences();
571 protected boolean isOutputVariable(PsiVariable var) {
572 return ExtractMethodProcessor.this.isOutputVariable(var);
575 protected boolean isVoidReturn() {
576 return myArtificialOutputVariable != null && !(myArtificialOutputVariable instanceof PsiField);
580 protected void checkMethodConflicts(MultiMap<PsiElement, String> conflicts) {
581 super.checkMethodConflicts(conflicts);
582 final VariableData[] parameters = getChosenParameters();
583 final Map<String, PsiLocalVariable> vars = new HashMap<String, PsiLocalVariable>();
584 for (PsiElement element : myElements) {
585 element.accept(new JavaRecursiveElementWalkingVisitor() {
587 public void visitLocalVariable(PsiLocalVariable variable) {
588 super.visitLocalVariable(variable);
589 vars.put(variable.getName(), variable);
593 public void visitClass(PsiClass aClass) {}
596 for (VariableData parameter : parameters) {
597 final String paramName = parameter.name;
598 final PsiLocalVariable variable = vars.get(paramName);
599 if (variable != null) {
600 conflicts.putValue(variable, "Variable with name " + paramName + " is already defined in the selected scope");
607 public PsiExpression[] findOccurrences() {
608 if (myExpression != null) {
609 return new PsiExpression[] {myExpression};
611 if (myOutputVariable != null) {
612 final PsiElement scope = myOutputVariable instanceof PsiLocalVariable
613 ? RefactoringUtil.getVariableScope((PsiLocalVariable)myOutputVariable)
614 : PsiTreeUtil.findCommonParent(myElements);
615 return CodeInsightUtil.findReferenceExpressions(scope, myOutputVariable);
617 final List<PsiStatement> filter = ContainerUtil.filter(myExitStatements, new Condition<PsiStatement>() {
619 public boolean value(PsiStatement statement) {
620 return statement instanceof PsiReturnStatement && ((PsiReturnStatement)statement).getReturnValue() != null;
623 final List<PsiExpression> map = ContainerUtil.map(filter, new Function<PsiStatement, PsiExpression>() {
625 public PsiExpression fun(PsiStatement statement) {
626 return ((PsiReturnStatement)statement).getReturnValue();
629 return map.toArray(new PsiExpression[map.size()]);
632 private Nullness initNullness() {
633 if (!PsiUtil.isLanguageLevel5OrHigher(myElements[0]) || PsiUtil.resolveClassInType(myReturnType) == null) return null;
634 final NullableNotNullManager manager = NullableNotNullManager.getInstance(myProject);
635 final PsiClass nullableAnnotationClass = JavaPsiFacade.getInstance(myProject)
636 .findClass(manager.getDefaultNullable(), myElements[0].getResolveScope());
637 if (nullableAnnotationClass != null) {
638 final PsiElement elementInCopy = myTargetClass.getContainingFile().copy().findElementAt(myTargetClass.getTextOffset());
639 final PsiClass classCopy = PsiTreeUtil.getParentOfType(elementInCopy, PsiClass.class);
640 if (classCopy == null) {
643 final PsiMethod emptyMethod = (PsiMethod)classCopy.addAfter(generateEmptyMethod("name"), classCopy.getLBrace());
644 prepareMethodBody(emptyMethod, false);
645 if (myNotNullConditionalCheck || myNullConditionalCheck) {
646 return Nullness.NULLABLE;
648 return DfaUtil.inferMethodNullity(emptyMethod);
653 protected String[] suggestInitialMethodName() {
654 if (StringUtil.isEmpty(myInitialMethodName)) {
655 final Set<String> initialMethodNames = new LinkedHashSet<String>();
656 final JavaCodeStyleManagerImpl codeStyleManager = (JavaCodeStyleManagerImpl)JavaCodeStyleManager.getInstance(myProject);
657 if (myExpression != null || !(myReturnType instanceof PsiPrimitiveType)) {
658 final String[] names = codeStyleManager.suggestVariableName(VariableKind.FIELD, null, myExpression, myReturnType).names;
659 for (String name : names) {
660 initialMethodNames.add(codeStyleManager.variableNameToPropertyName(name, VariableKind.FIELD));
664 if (myOutputVariable != null) {
665 final VariableKind outKind = codeStyleManager.getVariableKind(myOutputVariable);
666 final SuggestedNameInfo nameInfo = codeStyleManager
667 .suggestVariableName(VariableKind.FIELD, codeStyleManager.variableNameToPropertyName(myOutputVariable.getName(), outKind), null, myOutputVariable.getType());
668 for (String name : nameInfo.names) {
669 initialMethodNames.add(codeStyleManager.variableNameToPropertyName(name, VariableKind.FIELD));
673 final String nameByComment = getNameByComment();
674 final PsiField field = JavaPsiFacade.getElementFactory(myProject).createField("fieldNameToReplace", myReturnType instanceof PsiEllipsisType ? ((PsiEllipsisType)myReturnType).toArrayType() : myReturnType);
675 final List<String> getters = new ArrayList<String>(ContainerUtil.map(initialMethodNames, new Function<String, String>() {
677 public String fun(String propertyName) {
678 if (!PsiNameHelper.getInstance(myProject).isIdentifier(propertyName)) {
679 LOG.info(propertyName + "; " + myExpression);
682 field.setName(propertyName);
683 return GenerateMembersUtil.suggestGetterName(field);
686 ContainerUtil.addIfNotNull(nameByComment, getters);
687 return ArrayUtil.toStringArray(getters);
689 return new String[] {myInitialMethodName};
692 private String getNameByComment() {
693 PsiElement prevSibling = PsiTreeUtil.skipSiblingsBackward(myElements[0], PsiWhiteSpace.class);
694 if (prevSibling instanceof PsiComment && ((PsiComment)prevSibling).getTokenType() == JavaTokenType.END_OF_LINE_COMMENT) {
695 final String text = StringUtil.decapitalize(StringUtil.capitalizeWords(prevSibling.getText().trim().substring(2), true)).replaceAll(" ", "");
696 if (PsiNameHelper.getInstance(myProject).isIdentifier(text) && text.length() < 20) {
703 public boolean isOutputVariable(PsiVariable var) {
704 return ArrayUtil.find(myOutputVariables, var) != -1;
707 public boolean showDialog() {
708 return showDialog(true);
712 public void testRun() throws IncorrectOperationException {
715 ExtractMethodHandler.run(myProject, myEditor, this);
719 public void testNullness() {
720 myNullness = initNullness();
724 public void testPrepare() {
725 myInputVariables.setFoldingAvailable(myInputVariables.isFoldingSelectedByDefault());
726 myMethodName = myInitialMethodName;
727 myVariableDatum = new VariableData[myInputVariables.getInputVariables().size()];
728 for (int i = 0; i < myInputVariables.getInputVariables().size(); i++) {
729 myVariableDatum[i] = myInputVariables.getInputVariables().get(i);
734 public void testTargetClass(PsiClass targetClass) {
735 if (targetClass != null) {
736 myTargetClass = targetClass;
737 myNeedChangeContext = true;
742 public void testPrepare(PsiType returnType, boolean makeStatic) throws PrepareFailedException{
744 if (!isCanBeStatic()) {
745 throw new PrepareFailedException("Failed to make static", myElements[0]);
747 myInputVariables.setPassFields(true);
750 if (PsiType.VOID.equals(myReturnType)) {
751 myArtificialOutputVariable = getArtificialOutputVariable();
754 if (returnType != null) {
755 myReturnType = returnType;
760 public void doNotPassParameter(int i) {
761 myVariableDatum[i].passAsParameter = false;
765 public void changeParamName(int i, String param) {
766 myVariableDatum[i].name = param;
770 * Invoked in command and in atomic action
772 public void doRefactoring() throws IncorrectOperationException {
777 LogicalPosition pos1;
778 if (myEditor != null) {
779 int col = myEditor.getCaretModel().getLogicalPosition().column;
780 int line = myEditor.getCaretModel().getLogicalPosition().line;
781 pos1 = new LogicalPosition(line, col);
782 LogicalPosition pos = new LogicalPosition(0, 0);
783 myEditor.getCaretModel().moveToLogicalPosition(pos);
788 final SearchScope processConflictsScope = myMethodVisibility.equals(PsiModifier.PRIVATE) ?
789 new LocalSearchScope(myTargetClass) :
790 GlobalSearchScope.projectScope(myProject);
792 final Map<PsiMethodCallExpression, PsiMethod> overloadsResolveMap = new HashMap<PsiMethodCallExpression, PsiMethod>();
793 final Runnable collectOverloads = new Runnable() {
795 ApplicationManager.getApplication().runReadAction(new Runnable() {
797 Map<PsiMethodCallExpression, PsiMethod> overloads =
798 ExtractMethodUtil.encodeOverloadTargets(myTargetClass, processConflictsScope, myMethodName, myCodeFragmentMember);
799 overloadsResolveMap.putAll(overloads);
804 final Runnable extract = new Runnable() {
807 ExtractMethodUtil.decodeOverloadTargets(overloadsResolveMap, myExtractedMethod, myCodeFragmentMember);
810 if (ApplicationManager.getApplication().isWriteAccessAllowed()) {
811 collectOverloads.run();
814 if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(collectOverloads, "Collect overloads...", true, myProject)) return;
815 ApplicationManager.getApplication().runWriteAction(extract);
818 if (myEditor != null) {
819 myEditor.getCaretModel().moveToLogicalPosition(pos1);
820 int offset = myMethodCall.getMethodExpression().getTextRange().getStartOffset();
821 myEditor.getCaretModel().moveToOffset(offset);
822 myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
823 myEditor.getSelectionModel().removeSelection();
828 private DuplicatesFinder initDuplicates() {
829 List<PsiElement> elements = new ArrayList<PsiElement>();
830 for (PsiElement element : myElements) {
831 if (!(element instanceof PsiWhiteSpace || element instanceof PsiComment)) {
832 elements.add(element);
836 if (myExpression != null) {
837 DuplicatesFinder finder = new DuplicatesFinder(PsiUtilCore.toPsiElementArray(elements), myInputVariables.copy(),
838 new ArrayList<PsiVariable>());
839 myDuplicates = finder.findDuplicates(myTargetClass);
842 else if (elements.size() > 0){
843 DuplicatesFinder myDuplicatesFinder = new DuplicatesFinder(PsiUtilCore.toPsiElementArray(elements), myInputVariables.copy(),
844 myOutputVariable != null ? new VariableReturnValue(myOutputVariable) : null,
845 Arrays.asList(myOutputVariables));
846 myDuplicates = myDuplicatesFinder.findDuplicates(myTargetClass);
847 return myDuplicatesFinder;
849 myDuplicates = new ArrayList<Match>();
854 public void doExtract() throws IncorrectOperationException {
856 PsiMethod newMethod = generateEmptyMethod();
858 myExpression = myInputVariables.replaceWrappedReferences(myElements, myExpression);
859 renameInputVariables();
861 LOG.assertTrue(myElements[0].isValid());
863 PsiCodeBlock body = newMethod.getBody();
864 myMethodCall = generateMethodCall(null, true);
866 LOG.assertTrue(myElements[0].isValid());
868 final PsiStatement exitStatementCopy = prepareMethodBody(newMethod, true);
870 if (myExpression == null) {
871 if (myNeedChangeContext && isNeedToChangeCallContext()) {
872 for (PsiElement element : myElements) {
873 ChangeContextUtil.encodeContextInfo(element, false);
877 if (myNullConditionalCheck) {
878 final String varName = myOutputVariable.getName();
879 if (isDeclaredInside(myOutputVariable)) {
880 declareVariableAtMethodCallLocation(varName);
883 PsiExpressionStatement assignmentExpression =
884 (PsiExpressionStatement)myElementFactory.createStatementFromText(varName + "=x;", null);
885 assignmentExpression = (PsiExpressionStatement)addToMethodCallLocation(assignmentExpression);
887 (PsiMethodCallExpression)((PsiAssignmentExpression)assignmentExpression.getExpression()).getRExpression().replace(myMethodCall);
889 declareNecessaryVariablesAfterCall(myOutputVariable);
890 PsiIfStatement ifStatement;
891 if (myHasReturnStatementOutput) {
892 ifStatement = (PsiIfStatement)myElementFactory.createStatementFromText("if (" + varName + "==null) return null;", null);
894 else if (myGenerateConditionalExit) {
895 if (myFirstExitStatementCopy instanceof PsiReturnStatement && ((PsiReturnStatement)myFirstExitStatementCopy).getReturnValue() != null) {
896 ifStatement = (PsiIfStatement)myElementFactory.createStatementFromText("if (" + varName + "==null) return null;", null);
899 ifStatement = (PsiIfStatement)myElementFactory.createStatementFromText("if (" + varName + "==null) " + myFirstExitStatementCopy.getText(), null);
903 ifStatement = (PsiIfStatement)myElementFactory.createStatementFromText("if (" + varName + "==null) return;", null);
905 ifStatement = (PsiIfStatement)addToMethodCallLocation(ifStatement);
906 CodeStyleManager.getInstance(myProject).reformat(ifStatement);
908 else if (myNotNullConditionalCheck) {
909 String varName = myOutputVariable != null ? myOutputVariable.getName() : "x";
910 varName = declareVariableAtMethodCallLocation(varName, myReturnType instanceof PsiPrimitiveType ? ((PsiPrimitiveType)myReturnType).getBoxedType(myCodeFragmentMember) : myReturnType);
911 addToMethodCallLocation(myElementFactory.createStatementFromText("if (" + varName + " != null) return " + varName + ";", null));
913 else if (myGenerateConditionalExit) {
914 PsiIfStatement ifStatement = (PsiIfStatement)myElementFactory.createStatementFromText("if (a) b;", null);
915 ifStatement = (PsiIfStatement)addToMethodCallLocation(ifStatement);
916 myMethodCall = (PsiMethodCallExpression)ifStatement.getCondition().replace(myMethodCall);
917 myFirstExitStatementCopy = (PsiStatement)ifStatement.getThenBranch().replace(myFirstExitStatementCopy);
918 CodeStyleManager.getInstance(myProject).reformat(ifStatement);
920 else if (myOutputVariable != null || isArtificialOutputUsed()) {
921 boolean toDeclare = isArtificialOutputUsed() ? !(myArtificialOutputVariable instanceof PsiField) : isDeclaredInside(myOutputVariable);
922 String name = isArtificialOutputUsed() ? myArtificialOutputVariable.getName() : myOutputVariable.getName();
924 PsiExpressionStatement statement = (PsiExpressionStatement)myElementFactory.createStatementFromText(name + "=x;", null);
925 statement = (PsiExpressionStatement)myStyleManager.reformat(statement);
926 statement = (PsiExpressionStatement)addToMethodCallLocation(statement);
927 PsiAssignmentExpression assignment = (PsiAssignmentExpression)statement.getExpression();
928 myMethodCall = (PsiMethodCallExpression)assignment.getRExpression().replace(myMethodCall);
931 declareVariableAtMethodCallLocation(name);
934 else if (myHasReturnStatementOutput) {
935 PsiStatement statement = myElementFactory.createStatementFromText("return x;", null);
936 statement = (PsiStatement)addToMethodCallLocation(statement);
937 myMethodCall = (PsiMethodCallExpression)((PsiReturnStatement)statement).getReturnValue().replace(myMethodCall);
940 PsiStatement statement = myElementFactory.createStatementFromText("x();", null);
941 statement = (PsiStatement)addToMethodCallLocation(statement);
942 myMethodCall = (PsiMethodCallExpression)((PsiExpressionStatement)statement).getExpression().replace(myMethodCall);
944 if (myHasReturnStatement && !myHasReturnStatementOutput && !hasNormalExit()) {
945 PsiStatement statement = myElementFactory.createStatementFromText("return;", null);
946 addToMethodCallLocation(statement);
948 else if (!myGenerateConditionalExit && exitStatementCopy != null) {
949 addToMethodCallLocation(exitStatementCopy);
952 if (!myNullConditionalCheck && !myNotNullConditionalCheck) {
953 declareNecessaryVariablesAfterCall(myOutputVariable);
959 PsiExpression expression2Replace = myExpression;
960 if (myExpression instanceof PsiAssignmentExpression) {
961 expression2Replace = ((PsiAssignmentExpression)myExpression).getRExpression();
962 } else if (myExpression instanceof PsiPostfixExpression || myExpression instanceof PsiPrefixExpression) {
963 final IElementType elementType = myExpression instanceof PsiPostfixExpression
964 ? ((PsiPostfixExpression)myExpression).getOperationTokenType()
965 : ((PsiPrefixExpression)myExpression).getOperationTokenType();
966 if (elementType == JavaTokenType.PLUSPLUS || elementType == JavaTokenType.MINUSMINUS) {
967 PsiExpression operand = myExpression instanceof PsiPostfixExpression ? ((PsiPostfixExpression)myExpression).getOperand() :
968 ((PsiPrefixExpression)myExpression).getOperand();
970 ((PsiBinaryExpression)myExpression.replace(myElementFactory.createExpressionFromText(operand.getText() + " + x", operand))).getROperand();
974 myExpression = (PsiExpression)IntroduceVariableBase.replace(expression2Replace, myMethodCall, myProject);
975 myMethodCall = PsiTreeUtil.getParentOfType(myExpression.findElementAt(myExpression.getText().indexOf(myMethodCall.getText())), PsiMethodCallExpression.class);
976 declareNecessaryVariablesAfterCall(myOutputVariable);
979 if (myAnchor instanceof PsiField) {
980 ((PsiField)myAnchor).normalizeDeclaration();
983 adjustFinalParameters(newMethod);
985 for (VariableData data : myVariableDatum) {
986 if (!data.passAsParameter) continue;
987 final PsiParameter psiParameter = newMethod.getParameterList().getParameters()[i++];
988 final PsiType paramType = psiParameter.getType();
989 for (PsiReference reference : ReferencesSearch.search(psiParameter, new LocalSearchScope(body))){
990 final PsiElement element = reference.getElement();
991 if (element != null) {
992 final PsiElement parent = element.getParent();
993 if (parent instanceof PsiTypeCastExpression) {
994 final PsiTypeCastExpression typeCastExpression = (PsiTypeCastExpression)parent;
995 final PsiTypeElement castType = typeCastExpression.getCastType();
996 if (castType != null && Comparing.equal(castType.getType(), paramType)) {
997 RedundantCastUtil.removeCast(typeCastExpression);
1004 if (myNullness != null &&
1005 PsiUtil.resolveClassInType(newMethod.getReturnType()) != null &&
1006 PropertiesComponent.getInstance(myProject).getBoolean(ExtractMethodDialog.EXTRACT_METHOD_GENERATE_ANNOTATIONS, true)) {
1007 final NullableNotNullManager notNullManager = NullableNotNullManager.getInstance(myProject);
1008 AddNullableNotNullAnnotationFix annotationFix;
1009 switch (myNullness) {
1011 annotationFix = new AddNullableNotNullAnnotationFix(notNullManager.getDefaultNotNull(), newMethod);
1014 annotationFix = new AddNullableNotNullAnnotationFix(notNullManager.getDefaultNullable(), newMethod);
1017 annotationFix = null;
1019 if (annotationFix != null) {
1020 annotationFix.invoke(myProject, myTargetClass.getContainingFile(), newMethod, newMethod);
1024 myExtractedMethod = addExtractedMethod(newMethod);
1025 if (isNeedToChangeCallContext() && myNeedChangeContext) {
1026 ChangeContextUtil.decodeContextInfo(myExtractedMethod, myTargetClass, RefactoringChangeUtil.createThisExpression(myManager, null));
1027 if (myMethodCall.resolveMethod() != myExtractedMethod) {
1028 final PsiReferenceExpression methodExpression = myMethodCall.getMethodExpression();
1029 RefactoringChangeUtil.qualifyReference(methodExpression, myExtractedMethod, PsiUtil.getEnclosingStaticElement(methodExpression, myTargetClass) != null ? myTargetClass : null);
1034 protected PsiMethod addExtractedMethod(PsiMethod newMethod) {
1035 return (PsiMethod)myTargetClass.addAfter(newMethod, myAnchor);
1039 private PsiStatement prepareMethodBody(PsiMethod newMethod, boolean doExtract) {
1040 PsiCodeBlock body = newMethod.getBody();
1041 if (myExpression != null) {
1042 declareNecessaryVariablesInsideBody(body);
1043 if (myHasExpressionOutput) {
1044 PsiReturnStatement returnStatement = (PsiReturnStatement)myElementFactory.createStatementFromText("return x;", null);
1045 final PsiExpression returnValue = RefactoringUtil.convertInitializerToNormalExpression(myExpression, myForcedReturnType);
1046 returnStatement.getReturnValue().replace(returnValue);
1047 body.add(returnStatement);
1050 PsiExpressionStatement statement = (PsiExpressionStatement)myElementFactory.createStatementFromText("x;", null);
1051 statement.getExpression().replace(myExpression);
1052 body.add(statement);
1057 final boolean hasNormalExit = hasNormalExit();
1058 String outVariableName = myOutputVariable != null ? getNewVariableName(myOutputVariable) : null;
1059 PsiReturnStatement returnStatement;
1060 if (myNullConditionalCheck) {
1061 returnStatement = (PsiReturnStatement)myElementFactory.createStatementFromText("return null;", null);
1062 } else if (myOutputVariable != null) {
1063 returnStatement = (PsiReturnStatement)myElementFactory.createStatementFromText("return " + outVariableName + ";", null);
1065 else if (myGenerateConditionalExit) {
1066 returnStatement = (PsiReturnStatement)myElementFactory.createStatementFromText("return true;", null);
1069 returnStatement = (PsiReturnStatement)myElementFactory.createStatementFromText("return;", null);
1072 PsiStatement exitStatementCopy = !doExtract || myNotNullConditionalCheck ? null : myControlFlowWrapper.getExitStatementCopy(returnStatement, myElements);
1075 declareNecessaryVariablesInsideBody(body);
1077 body.addRange(myElements[0], myElements[myElements.length - 1]);
1078 if (myNullConditionalCheck) {
1079 body.add(myElementFactory.createStatementFromText("return " + myOutputVariable.getName() + ";", null));
1081 else if (myNotNullConditionalCheck) {
1082 body.add(myElementFactory.createStatementFromText("return null;", null));
1084 else if (myGenerateConditionalExit) {
1085 body.add(myElementFactory.createStatementFromText("return false;", null));
1087 else if (!myHasReturnStatement && hasNormalExit && myOutputVariable != null) {
1088 final PsiReturnStatement insertedReturnStatement = (PsiReturnStatement)body.add(returnStatement);
1089 if (myOutputVariables.length == 1) {
1090 final PsiExpression returnValue = insertedReturnStatement.getReturnValue();
1091 if (returnValue instanceof PsiReferenceExpression) {
1092 final PsiElement resolved = ((PsiReferenceExpression)returnValue).resolve();
1093 if (resolved instanceof PsiLocalVariable && Comparing.strEqual(((PsiVariable)resolved).getName(), outVariableName)) {
1094 final PsiStatement statement = PsiTreeUtil.getPrevSiblingOfType(insertedReturnStatement, PsiStatement.class);
1095 if (statement instanceof PsiDeclarationStatement) {
1096 final PsiElement[] declaredElements = ((PsiDeclarationStatement)statement).getDeclaredElements();
1097 if (ArrayUtil.find(declaredElements, resolved) != -1) {
1098 InlineUtil.inlineVariable((PsiVariable)resolved, ((PsiVariable)resolved).getInitializer(),
1099 (PsiReferenceExpression)returnValue);
1107 else if (isArtificialOutputUsed()) {
1108 body.add(myElementFactory.createStatementFromText("return " + myArtificialOutputVariable.getName() + ";", null));
1110 return exitStatementCopy;
1113 private boolean isArtificialOutputUsed() {
1114 return myArtificialOutputVariable != null && !PsiType.VOID.equals(myReturnType) && !myIsChainedConstructor;
1117 private boolean hasNormalExit() {
1118 boolean hasNormalExit = false;
1119 PsiElement lastElement = myElements[myElements.length - 1];
1120 if (!(lastElement instanceof PsiReturnStatement || lastElement instanceof PsiBreakStatement ||
1121 lastElement instanceof PsiContinueStatement)) {
1122 hasNormalExit = true;
1124 return hasNormalExit;
1127 protected boolean isNeedToChangeCallContext() {
1131 private void declareVariableAtMethodCallLocation(String name) {
1132 declareVariableAtMethodCallLocation(name, myReturnType);
1135 private String declareVariableAtMethodCallLocation(String name, PsiType type) {
1136 if (myControlFlowWrapper.getOutputVariables(false).length == 0) {
1137 PsiElement lastStatement = PsiTreeUtil.getNextSiblingOfType(myEnclosingBlockStatement != null ? myEnclosingBlockStatement : myElements[myElements.length - 1], PsiStatement.class);
1138 if (lastStatement != null) {
1139 name = JavaCodeStyleManager.getInstance(myProject).suggestUniqueVariableName(name, lastStatement, true);
1142 PsiDeclarationStatement statement = myElementFactory.createVariableDeclarationStatement(name, type, myMethodCall);
1144 (PsiDeclarationStatement)JavaCodeStyleManager.getInstance(myProject).shortenClassReferences(addToMethodCallLocation(statement));
1145 PsiVariable var = (PsiVariable)statement.getDeclaredElements()[0];
1146 myMethodCall = (PsiMethodCallExpression)var.getInitializer();
1147 if (myOutputVariable != null) {
1148 var.getModifierList().replace(myOutputVariable.getModifierList());
1153 private void adjustFinalParameters(final PsiMethod method) throws IncorrectOperationException {
1154 final IncorrectOperationException[] exc = new IncorrectOperationException[1];
1156 final PsiParameter[] parameters = method.getParameterList().getParameters();
1157 if (parameters.length > 0) {
1158 if (CodeStyleSettingsManager.getSettings(myProject).GENERATE_FINAL_PARAMETERS) {
1159 method.accept(new JavaRecursiveElementVisitor() {
1161 @Override public void visitReferenceExpression(PsiReferenceExpression expression) {
1162 final PsiElement resolved = expression.resolve();
1163 if (resolved != null) {
1164 final int index = ArrayUtil.find(parameters, resolved);
1166 final PsiParameter param = parameters[index];
1167 if (param.hasModifierProperty(PsiModifier.FINAL) && PsiUtil.isAccessedForWriting(expression)) {
1169 PsiUtil.setModifierProperty(param, PsiModifier.FINAL, false);
1171 catch (IncorrectOperationException e) {
1177 super.visitReferenceExpression(expression);
1182 method.accept(new JavaRecursiveElementVisitor() {
1183 @Override public void visitReferenceExpression(PsiReferenceExpression expression) {
1184 final PsiElement resolved = expression.resolve();
1185 final int index = ArrayUtil.find(parameters, resolved);
1187 final PsiParameter param = parameters[index];
1188 if (!param.hasModifierProperty(PsiModifier.FINAL) && RefactoringUtil.isInsideAnonymousOrLocal(expression, method)) {
1190 PsiUtil.setModifierProperty(param, PsiModifier.FINAL, true);
1192 catch (IncorrectOperationException e) {
1197 super.visitReferenceExpression(expression);
1201 if (exc[0] != null) {
1207 public List<Match> getDuplicates() {
1208 if (myIsChainedConstructor) {
1209 return filterChainedConstructorDuplicates(myDuplicates);
1211 return myDuplicates;
1214 private static List<Match> filterChainedConstructorDuplicates(final List<Match> duplicates) {
1215 List<Match> result = new ArrayList<Match>();
1216 for(Match duplicate: duplicates) {
1217 final PsiElement matchStart = duplicate.getMatchStart();
1218 final PsiMethod method = PsiTreeUtil.getParentOfType(matchStart, PsiMethod.class);
1219 if (method != null && method.isConstructor()) {
1220 final PsiCodeBlock body = method.getBody();
1222 final PsiStatement[] psiStatements = body.getStatements();
1223 if (psiStatements.length > 0 && matchStart == psiStatements [0]) {
1224 result.add(duplicate);
1232 public PsiElement processMatch(Match match) throws IncorrectOperationException {
1233 MatchUtil.changeSignature(match, myExtractedMethod);
1234 if (RefactoringUtil.isInStaticContext(match.getMatchStart(), myExtractedMethod.getContainingClass())) {
1235 PsiUtil.setModifierProperty(myExtractedMethod, PsiModifier.STATIC, true);
1237 final PsiMethodCallExpression methodCallExpression = generateMethodCall(match.getInstanceExpression(), false);
1239 ArrayList<VariableData> datas = new ArrayList<VariableData>();
1240 for (final VariableData variableData : myVariableDatum) {
1241 if (variableData.passAsParameter) {
1242 datas.add(variableData);
1245 final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject);
1246 for (VariableData data : datas) {
1247 final List<PsiElement> parameterValue = match.getParameterValues(data.variable);
1248 if (parameterValue != null) {
1249 for (PsiElement val : parameterValue) {
1250 if (val instanceof PsiExpression) {
1251 final PsiType exprType = ((PsiExpression)val).getType();
1252 if (exprType != null && !TypeConversionUtil.isAssignable(data.type, exprType)) {
1253 final PsiTypeCastExpression cast = (PsiTypeCastExpression)elementFactory.createExpressionFromText("(A)a", val);
1254 cast.getCastType().replace(elementFactory.createTypeElement(data.type));
1255 cast.getOperand().replace(val.copy());
1259 methodCallExpression.getArgumentList().add(val);
1262 methodCallExpression.getArgumentList().add(myElementFactory.createExpressionFromText(data.variable.getName(), methodCallExpression));
1265 return match.replace(myExtractedMethod, methodCallExpression, myOutputVariable);
1268 protected void deleteExtracted() throws IncorrectOperationException {
1269 if (myEnclosingBlockStatement == null) {
1270 myElements[0].getParent().deleteChildRange(myElements[0], myElements[myElements.length - 1]);
1273 myEnclosingBlockStatement.delete();
1277 protected PsiElement addToMethodCallLocation(PsiStatement statement) throws IncorrectOperationException {
1278 if (myEnclosingBlockStatement == null) {
1279 PsiElement containingStatement = myElements[0] instanceof PsiComment ? myElements[0] : PsiTreeUtil.getParentOfType(myExpression != null ? myExpression : myElements[0], PsiStatement.class, false);
1280 if (containingStatement == null) {
1281 containingStatement = PsiTreeUtil.getParentOfType(myExpression != null ? myExpression : myElements[0], PsiComment.class, false);
1284 return containingStatement.getParent().addBefore(statement, containingStatement);
1287 return myEnclosingBlockStatement.getParent().addBefore(statement, myEnclosingBlockStatement);
1291 private void renameInputVariables() throws IncorrectOperationException {
1292 //when multiple input variables should have the same name, unique names are generated
1293 //without reverse, the second rename would rename variable without a prefix into second one though it was already renamed
1294 LocalSearchScope localSearchScope = null;
1295 for (int i = myVariableDatum.length - 1; i >= 0; i--) {
1296 VariableData data = myVariableDatum[i];
1297 PsiVariable variable = data.variable;
1298 if (!data.name.equals(variable.getName()) || variable instanceof PsiField) {
1299 if (localSearchScope == null) {
1300 localSearchScope = new LocalSearchScope(myElements);
1303 for (PsiReference reference : ReferencesSearch.search(variable, localSearchScope)) {
1304 reference.handleElementRename(data.name);
1306 final PsiElement element = reference.getElement();
1307 if (element instanceof PsiReferenceExpression) {
1308 final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)element;
1309 final PsiExpression qualifierExpression = referenceExpression.getQualifierExpression();
1310 if (qualifierExpression instanceof PsiThisExpression || qualifierExpression instanceof PsiSuperExpression) {
1311 referenceExpression.setQualifierExpression(null);
1319 public PsiClass getTargetClass() {
1320 return myTargetClass;
1323 public PsiType getReturnType() {
1324 return myReturnType;
1327 private PsiMethod generateEmptyMethod() throws IncorrectOperationException {
1328 return generateEmptyMethod(myMethodName);
1331 public PsiMethod generateEmptyMethod(String methodName) throws IncorrectOperationException {
1332 PsiMethod newMethod;
1333 if (myIsChainedConstructor) {
1334 newMethod = myElementFactory.createConstructor();
1337 newMethod = myElementFactory.createMethod(methodName, myReturnType);
1338 PsiUtil.setModifierProperty(newMethod, PsiModifier.STATIC, isStatic());
1340 PsiUtil.setModifierProperty(newMethod, myMethodVisibility, true);
1341 if (getTypeParameterList() != null) {
1342 newMethod.getTypeParameterList().replace(getTypeParameterList());
1344 PsiCodeBlock body = newMethod.getBody();
1345 LOG.assertTrue(body != null);
1347 boolean isFinal = CodeStyleSettingsManager.getSettings(myProject).GENERATE_FINAL_PARAMETERS;
1348 PsiParameterList list = newMethod.getParameterList();
1349 for (VariableData data : myVariableDatum) {
1350 if (data.passAsParameter) {
1351 PsiParameter parm = myElementFactory.createParameter(data.name, data.type);
1352 copyParamAnnotations(parm);
1354 PsiUtil.setModifierProperty(parm, PsiModifier.FINAL, true);
1359 @NonNls StringBuilder buffer = new StringBuilder();
1361 buffer.append("final ");
1363 buffer.append("int ");
1364 buffer.append(data.name);
1365 buffer.append("=;");
1366 String text = buffer.toString();
1368 PsiDeclarationStatement declaration = (PsiDeclarationStatement)myElementFactory.createStatementFromText(text, null);
1369 declaration = (PsiDeclarationStatement)myStyleManager.reformat(declaration);
1370 final PsiTypeElement typeElement = myElementFactory.createTypeElement(data.type);
1371 ((PsiVariable)declaration.getDeclaredElements()[0]).getTypeElement().replace(typeElement);
1372 body.add(declaration);
1376 PsiReferenceList throwsList = newMethod.getThrowsList();
1377 for (PsiClassType exception : getThrownExceptions()) {
1378 throwsList.add(JavaPsiFacade.getInstance(myManager.getProject()).getElementFactory().createReferenceElementByType(exception));
1381 if (myTargetClass.isInterface() && PsiUtil.isLanguageLevel8OrHigher(myTargetClass)) {
1382 final PsiMethod containingMethod = PsiTreeUtil.getParentOfType(myCodeFragmentMember, PsiMethod.class, false);
1383 if (containingMethod != null && containingMethod.hasModifierProperty(PsiModifier.DEFAULT)) {
1384 PsiUtil.setModifierProperty(newMethod, PsiModifier.DEFAULT, true);
1387 return (PsiMethod)myStyleManager.reformat(newMethod);
1390 private void copyParamAnnotations(PsiParameter parm) {
1391 final PsiVariable variable = PsiResolveHelper.SERVICE.getInstance(myProject).resolveReferencedVariable(parm.getName(), myElements[0]);
1392 if (variable instanceof PsiParameter) {
1393 final PsiModifierList modifierList = variable.getModifierList();
1394 if (modifierList != null) {
1395 for (PsiAnnotation annotation : modifierList.getAnnotations()) {
1396 if (SuppressWarnings.class.getName().equals(annotation.getQualifiedName())) continue;
1397 final PsiModifierList parmModifierList = parm.getModifierList();
1398 LOG.assertTrue(parmModifierList != null, parm);
1399 parmModifierList.add(annotation);
1406 protected PsiMethodCallExpression generateMethodCall(PsiExpression instanceQualifier, final boolean generateArgs) throws IncorrectOperationException {
1407 @NonNls StringBuilder buffer = new StringBuilder();
1409 final boolean skipInstanceQualifier;
1410 if (myIsChainedConstructor) {
1411 skipInstanceQualifier = true;
1412 buffer.append(PsiKeyword.THIS);
1415 skipInstanceQualifier = instanceQualifier == null || instanceQualifier instanceof PsiThisExpression;
1416 if (skipInstanceQualifier) {
1417 if (isNeedToChangeCallContext() && myNeedChangeContext) {
1418 boolean needsThisQualifier = false;
1419 PsiElement parent = myCodeFragmentMember;
1420 while (!myTargetClass.equals(parent)) {
1421 if (parent instanceof PsiMethod) {
1422 String methodName = ((PsiMethod)parent).getName();
1423 if (methodName.equals(myMethodName)) {
1424 needsThisQualifier = true;
1428 parent = parent.getParent();
1430 if (needsThisQualifier) {
1431 buffer.append(myTargetClass.getName());
1432 buffer.append(".this.");
1437 buffer.append("qqq.");
1440 buffer.append(myMethodName);
1445 for (VariableData data : myVariableDatum) {
1446 if (data.passAsParameter) {
1450 myInputVariables.appendCallArguments(data, buffer);
1456 String text = buffer.toString();
1458 PsiMethodCallExpression expr = (PsiMethodCallExpression)myElementFactory.createExpressionFromText(text, null);
1459 expr = (PsiMethodCallExpression)myStyleManager.reformat(expr);
1460 if (!skipInstanceQualifier) {
1461 PsiExpression qualifierExpression = expr.getMethodExpression().getQualifierExpression();
1462 LOG.assertTrue(qualifierExpression != null);
1463 qualifierExpression.replace(instanceQualifier);
1465 return (PsiMethodCallExpression)JavaCodeStyleManager.getInstance(myProject).shortenClassReferences(expr);
1468 private boolean chooseTargetClass(PsiElement codeFragment, final Pass<ExtractMethodProcessor> extractPass) throws PrepareFailedException {
1469 final List<PsiVariable> inputVariables = myControlFlowWrapper.getInputVariables(codeFragment, myElements, myOutputVariables);
1471 myNeedChangeContext = false;
1472 myTargetClass = myCodeFragmentMember instanceof PsiMember
1473 ? ((PsiMember)myCodeFragmentMember).getContainingClass()
1474 : PsiTreeUtil.getParentOfType(myCodeFragmentMember, PsiClass.class);
1475 if (!shouldAcceptCurrentTarget(extractPass, myTargetClass)) {
1477 final LinkedHashMap<PsiClass, List<PsiVariable>> classes = new LinkedHashMap<PsiClass, List<PsiVariable>>();
1478 final PsiElementProcessor<PsiClass> processor = new PsiElementProcessor<PsiClass>() {
1480 public boolean execute(@NotNull PsiClass selectedClass) {
1481 AnonymousTargetClassPreselectionUtil.rememberSelection(selectedClass, myTargetClass);
1482 final List<PsiVariable> array = classes.get(selectedClass);
1483 myNeedChangeContext = myTargetClass != selectedClass;
1484 myTargetClass = selectedClass;
1485 if (array != null) {
1486 for (PsiVariable variable : array) {
1487 if (!inputVariables.contains(variable)) {
1488 inputVariables.addAll(array);
1493 return applyChosenClassAndExtract(inputVariables, extractPass);
1495 catch (PrepareFailedException e) {
1496 if (myShowErrorDialogs) {
1497 CommonRefactoringUtil
1498 .showErrorHint(myProject, myEditor, e.getMessage(), ExtractMethodHandler.REFACTORING_NAME, HelpID.EXTRACT_METHOD);
1499 ExtractMethodHandler.highlightPrepareError(e, e.getFile(), myEditor, myProject);
1506 classes.put(myTargetClass, null);
1507 PsiElement target = myTargetClass.getParent();
1508 PsiElement targetMember = myTargetClass;
1510 if (target instanceof PsiFile) break;
1511 if (target instanceof PsiClass) {
1512 boolean success = true;
1513 final List<PsiVariable> array = new ArrayList<PsiVariable>();
1514 for (PsiElement el : myElements) {
1515 if (!ControlFlowUtil.collectOuterLocals(array, el, myCodeFragmentMember, targetMember)) {
1521 classes.put((PsiClass)target, array);
1522 if (shouldAcceptCurrentTarget(extractPass, target)) {
1523 return processor.execute((PsiClass)target);
1527 targetMember = target;
1528 target = target.getParent();
1531 if (classes.size() > 1) {
1532 final PsiClass[] psiClasses = classes.keySet().toArray(new PsiClass[classes.size()]);
1533 final PsiClass preselection = AnonymousTargetClassPreselectionUtil.getPreselection(classes.keySet(), psiClasses[0]);
1534 NavigationUtil.getPsiElementPopup(psiClasses, new PsiClassListCellRenderer(), "Choose Destination Class", processor, preselection)
1535 .showInBestPositionFor(myEditor);
1540 return applyChosenClassAndExtract(inputVariables, extractPass);
1543 private void declareNecessaryVariablesInsideBody(PsiCodeBlock body) throws IncorrectOperationException {
1544 List<PsiVariable> usedVariables = myControlFlowWrapper.getUsedVariablesInBody(ControlFlowUtil.findCodeFragment(myElements[0]), myOutputVariables);
1545 for (PsiVariable variable : usedVariables) {
1546 boolean toDeclare = !isDeclaredInside(variable) && myInputVariables.toDeclareInsideBody(variable);
1548 String name = variable.getName();
1549 PsiDeclarationStatement statement = myElementFactory.createVariableDeclarationStatement(name, variable.getType(), null);
1550 body.add(statement);
1554 if (myArtificialOutputVariable instanceof PsiField && !myIsChainedConstructor) {
1555 body.add(myElementFactory.createVariableDeclarationStatement(myArtificialOutputVariable.getName(), myArtificialOutputVariable.getType(), null));
1559 protected void declareNecessaryVariablesAfterCall(PsiVariable outputVariable) throws IncorrectOperationException {
1560 if (myHasExpressionOutput) return;
1561 List<PsiVariable> usedVariables = myControlFlowWrapper.getUsedVariables();
1562 Collection<ControlFlowUtil.VariableInfo> reassigned = myControlFlowWrapper.getInitializedTwice();
1563 for (PsiVariable variable : usedVariables) {
1564 boolean toDeclare = isDeclaredInside(variable) && !variable.equals(outputVariable);
1566 String name = variable.getName();
1567 PsiDeclarationStatement statement = myElementFactory.createVariableDeclarationStatement(name, variable.getType(), null);
1568 if (reassigned.contains(new ControlFlowUtil.VariableInfo(variable, null))) {
1569 final PsiElement[] psiElements = statement.getDeclaredElements();
1570 assert psiElements.length > 0;
1571 PsiVariable var = (PsiVariable) psiElements [0];
1572 PsiUtil.setModifierProperty(var, PsiModifier.FINAL, false);
1574 addToMethodCallLocation(statement);
1579 public PsiMethodCallExpression getMethodCall() {
1580 return myMethodCall;
1583 public void setMethodCall(PsiMethodCallExpression methodCall) {
1584 myMethodCall = methodCall;
1587 public boolean isDeclaredInside(PsiVariable variable) {
1588 if (variable instanceof ImplicitVariable) return false;
1591 if (myExpression != null) {
1592 final TextRange range = myExpression.getTextRange();
1593 startOffset = range.getStartOffset();
1594 endOffset = range.getEndOffset();
1596 startOffset = myElements[0].getTextRange().getStartOffset();
1597 endOffset = myElements[myElements.length - 1].getTextRange().getEndOffset();
1599 PsiIdentifier nameIdentifier = variable.getNameIdentifier();
1600 if (nameIdentifier == null) return false;
1601 final TextRange range = nameIdentifier.getTextRange();
1602 if (range == null) return false;
1603 int offset = range.getStartOffset();
1604 return startOffset <= offset && offset <= endOffset;
1607 private String getNewVariableName(PsiVariable variable) {
1608 for (VariableData data : myVariableDatum) {
1609 if (data.variable.equals(variable)) {
1613 return variable.getName();
1616 private static boolean shouldAcceptCurrentTarget(Pass<ExtractMethodProcessor> extractPass, PsiElement target) {
1617 return extractPass == null && !(target instanceof PsiAnonymousClass);
1620 private boolean applyChosenClassAndExtract(List<PsiVariable> inputVariables, @Nullable Pass<ExtractMethodProcessor> extractPass)
1621 throws PrepareFailedException {
1622 myStatic = shouldBeStatic();
1623 final Set<PsiField> fields = new LinkedHashSet<PsiField>();
1624 if (!PsiUtil.isLocalOrAnonymousClass(myTargetClass) && (myTargetClass.getContainingClass() == null || myTargetClass.hasModifierProperty(PsiModifier.STATIC))) {
1625 boolean canBeStatic = true;
1626 if (myTargetClass.isInterface()) {
1627 final PsiMethod containingMethod = PsiTreeUtil.getParentOfType(myCodeFragmentMember, PsiMethod.class, false);
1628 canBeStatic = containingMethod == null || containingMethod.hasModifierProperty(PsiModifier.STATIC);
1631 ElementNeedsThis needsThis = new ElementNeedsThis(myTargetClass) {
1633 protected void visitClassMemberReferenceElement(PsiMember classMember, PsiJavaCodeReferenceElement classMemberReference) {
1634 if (classMember instanceof PsiField && !classMember.hasModifierProperty(PsiModifier.STATIC)) {
1635 final PsiExpression expression = PsiTreeUtil.getParentOfType(classMemberReference, PsiExpression.class, false);
1636 if (expression == null || !PsiUtil.isAccessedForWriting(expression)) {
1637 fields.add((PsiField)classMember);
1641 super.visitClassMemberReferenceElement(classMember, classMemberReference);
1644 for (int i = 0; i < myElements.length && !needsThis.usesMembers(); i++) {
1645 PsiElement element = myElements[i];
1646 element.accept(needsThis);
1648 myCanBeStatic = !needsThis.usesMembers();
1651 myCanBeStatic = false;
1655 myCanBeStatic = false;
1658 myInputVariables = new InputVariables(inputVariables, myProject, new LocalSearchScope(myElements), isFoldingApplicable());
1659 myInputVariables.setUsedInstanceFields(fields);
1661 if (!checkExitPoints()){
1665 checkCanBeChainedConstructor();
1667 if (extractPass != null) {
1668 extractPass.pass(this);
1673 protected boolean isFoldingApplicable() {
1677 private void chooseAnchor() {
1678 myAnchor = myCodeFragmentMember;
1679 while (!myAnchor.getParent().equals(myTargetClass)) {
1680 myAnchor = myAnchor.getParent();
1684 private void showMultipleExitPointsMessage() {
1685 if (myShowErrorDialogs) {
1686 HighlightManager highlightManager = HighlightManager.getInstance(myProject);
1687 PsiStatement[] exitStatementsArray = myExitStatements.toArray(new PsiStatement[myExitStatements.size()]);
1688 EditorColorsManager manager = EditorColorsManager.getInstance();
1689 TextAttributes attributes = manager.getGlobalScheme().getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES);
1690 highlightManager.addOccurrenceHighlights(myEditor, exitStatementsArray, attributes, true, null);
1691 String message = RefactoringBundle
1692 .getCannotRefactorMessage(RefactoringBundle.message("there.are.multiple.exit.points.in.the.selected.code.fragment"));
1693 CommonRefactoringUtil.showErrorHint(myProject, myEditor, message, myRefactoringName, myHelpId);
1694 WindowManager.getInstance().getStatusBar(myProject).setInfo(RefactoringBundle.message("press.escape.to.remove.the.highlighting"));
1698 private void showMultipleOutputMessage(PsiType expressionType) {
1699 if (myShowErrorDialogs) {
1700 StringBuilder buffer = new StringBuilder();
1701 buffer.append(RefactoringBundle.getCannotRefactorMessage(
1702 RefactoringBundle.message("there.are.multiple.output.values.for.the.selected.code.fragment")));
1703 buffer.append("\n");
1704 if (myHasExpressionOutput) {
1705 buffer.append(" ").append(RefactoringBundle.message("expression.result")).append(": ");
1706 buffer.append(PsiFormatUtil.formatType(expressionType, 0, PsiSubstitutor.EMPTY));
1707 buffer.append(",\n");
1709 if (myGenerateConditionalExit) {
1710 buffer.append(" ").append(RefactoringBundle.message("boolean.method.result"));
1711 buffer.append(",\n");
1713 for (int i = 0; i < myOutputVariables.length; i++) {
1714 PsiVariable var = myOutputVariables[i];
1716 buffer.append(var.getName());
1717 buffer.append(" : ");
1718 buffer.append(PsiFormatUtil.formatType(var.getType(), 0, PsiSubstitutor.EMPTY));
1719 if (i < myOutputVariables.length - 1) {
1720 buffer.append(",\n");
1726 buffer.append("\nWould you like to Extract Method Object?");
1728 String message = buffer.toString();
1730 if (ApplicationManager.getApplication().isUnitTestMode()) throw new RuntimeException(message);
1731 RefactoringMessageDialog dialog = new RefactoringMessageDialog(myRefactoringName, message, myHelpId, "OptionPane.errorIcon", true,
1733 if (dialog.showAndGet()) {
1734 new ExtractMethodObjectHandler()
1735 .invoke(myProject, myEditor, myTargetClass.getContainingFile(), DataManager.getInstance().getDataContext());
1740 public PsiMethod getExtractedMethod() {
1741 return myExtractedMethod;
1744 public Boolean hasDuplicates() {
1745 List<Match> duplicates = getDuplicates();
1746 if (duplicates != null && !duplicates.isEmpty()) {
1750 if (myExtractedMethod != null) {
1751 final ExtractMethodSignatureSuggester suggester = new ExtractMethodSignatureSuggester(myProject, myExtractedMethod, myMethodCall, myVariableDatum);
1752 duplicates = suggester.getDuplicates(myExtractedMethod, myMethodCall, myInputVariables.getFolding());
1753 if (duplicates != null && !duplicates.isEmpty()) {
1754 myDuplicates = duplicates;
1755 myExtractedMethod = suggester.getExtractedMethod();
1756 myMethodCall = suggester.getMethodCall();
1757 myVariableDatum = suggester.getVariableData();
1759 final List<PsiVariable> outputVariables = new ArrayList<>();
1760 for (PsiReturnStatement statement : PsiUtil.findReturnStatements(myExtractedMethod)) {
1761 final PsiExpression returnValue = statement.getReturnValue();
1762 if (returnValue instanceof PsiReferenceExpression) {
1763 final PsiElement resolve = ((PsiReferenceExpression)returnValue).resolve();
1764 if (resolve instanceof PsiLocalVariable) {
1765 outputVariables.add((PsiVariable)resolve);
1770 if (outputVariables.size() == 1) {
1771 myOutputVariable = outputVariables.get(0);
1780 public boolean hasDuplicates(Set<VirtualFile> files) {
1781 final DuplicatesFinder finder = initDuplicates();
1783 final Boolean hasDuplicates = hasDuplicates();
1784 if (hasDuplicates == null || hasDuplicates) return true;
1785 if (finder != null) {
1786 final PsiManager psiManager = PsiManager.getInstance(myProject);
1787 for (VirtualFile file : files) {
1788 if (!finder.findDuplicates(psiManager.findFile(file)).isEmpty()) return true;
1795 public String getConfirmDuplicatePrompt(Match match) {
1796 final boolean needToBeStatic = RefactoringUtil.isInStaticContext(match.getMatchStart(), myExtractedMethod.getContainingClass());
1797 final String changedSignature = MatchUtil
1798 .getChangedSignature(match, myExtractedMethod, needToBeStatic, VisibilityUtil.getVisibilityStringToDisplay(myExtractedMethod));
1799 if (changedSignature != null) {
1800 return RefactoringBundle.message("replace.this.code.fragment.and.change.signature", changedSignature);
1802 if (needToBeStatic && !myExtractedMethod.hasModifierProperty(PsiModifier.STATIC)) {
1803 return RefactoringBundle.message("replace.this.code.fragment.and.make.method.static");
1809 public String getReplaceDuplicatesTitle(int idx, int size) {
1810 return RefactoringBundle.message("process.duplicates.title", idx, size);
1813 public InputVariables getInputVariables() {
1814 return myInputVariables;
1817 public PsiTypeParameterList getTypeParameterList() {
1818 return myTypeParameterList;
1821 public PsiClassType[] getThrownExceptions() {
1822 return myThrownExceptions;
1825 public boolean isStatic() {
1829 public boolean isCanBeStatic() {
1830 return myCanBeStatic;
1833 public PsiElement[] getElements() {
1837 public PsiVariable[] getOutputVariables() {
1838 return myOutputVariables;