update copyright
[fedora-idea.git] / java / java-impl / src / com / intellij / refactoring / extractMethodObject / ExtractMethodObjectProcessor.java
blobb9fd7943cb9e4f239b0cc05ac12689003b85bd9e
1 /*
2 * Copyright 2000-2009 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.
18 * User: anna
19 * Date: 06-May-2008
21 package com.intellij.refactoring.extractMethodObject;
23 import com.intellij.codeInsight.AnnotationUtil;
24 import com.intellij.openapi.diagnostic.Logger;
25 import com.intellij.openapi.editor.Editor;
26 import com.intellij.openapi.project.Project;
27 import com.intellij.openapi.ui.DialogWrapper;
28 import com.intellij.openapi.util.Comparing;
29 import com.intellij.openapi.util.text.StringUtil;
30 import com.intellij.psi.*;
31 import com.intellij.psi.codeStyle.CodeStyleManager;
32 import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
33 import com.intellij.psi.codeStyle.JavaCodeStyleManager;
34 import com.intellij.psi.codeStyle.VariableKind;
35 import com.intellij.psi.controlFlow.ControlFlowUtil;
36 import com.intellij.psi.impl.source.PsiImmediateClassType;
37 import com.intellij.psi.search.GlobalSearchScope;
38 import com.intellij.psi.search.searches.ReferencesSearch;
39 import com.intellij.psi.util.PropertyUtil;
40 import com.intellij.psi.util.PsiTreeUtil;
41 import com.intellij.psi.util.PsiUtil;
42 import com.intellij.refactoring.BaseRefactoringProcessor;
43 import com.intellij.refactoring.HelpID;
44 import com.intellij.refactoring.classMembers.MemberInfoBase;
45 import com.intellij.refactoring.changeSignature.ChangeSignatureProcessor;
46 import com.intellij.refactoring.changeSignature.ParameterInfoImpl;
47 import com.intellij.refactoring.extractMethod.AbstractExtractDialog;
48 import com.intellij.refactoring.extractMethod.ExtractMethodProcessor;
49 import com.intellij.refactoring.ui.MemberSelectionPanel;
50 import com.intellij.refactoring.util.RefactoringUtil;
51 import com.intellij.util.VisibilityUtil;
52 import com.intellij.refactoring.util.classMembers.MemberInfo;
53 import com.intellij.refactoring.util.duplicates.Match;
54 import com.intellij.usageView.UsageInfo;
55 import com.intellij.usageView.UsageViewDescriptor;
56 import com.intellij.usageView.UsageViewUtil;
57 import com.intellij.util.ArrayUtil;
58 import com.intellij.util.Function;
59 import com.intellij.util.IncorrectOperationException;
60 import org.jetbrains.annotations.NonNls;
61 import org.jetbrains.annotations.NotNull;
63 import javax.swing.*;
64 import java.util.*;
66 public class ExtractMethodObjectProcessor extends BaseRefactoringProcessor {
67 private static final Logger LOG = Logger.getInstance("#" + com.intellij.refactoring.extractMethodObject.ExtractMethodObjectProcessor.class.getName());
68 @NonNls public static final String REFACTORING_NAME = "Extract Method Object";
70 private final PsiElementFactory myElementFactory;
72 private final MyExtractMethodProcessor myExtractProcessor;
73 private boolean myCreateInnerClass = true;
74 private String myInnerClassName;
76 private boolean myMultipleExitPoints;
77 private PsiField[] myOutputFields;
79 private PsiMethod myInnerMethod;
80 private boolean myMadeStatic = false;
81 private final Set<MethodToMoveUsageInfo> myUsages = new HashSet<MethodToMoveUsageInfo>();
82 private PsiClass myInnerClass;
84 public ExtractMethodObjectProcessor(Project project, Editor editor, PsiElement[] elements, final String innerClassName) {
85 super(project);
86 myInnerClassName = innerClassName;
87 myExtractProcessor = new MyExtractMethodProcessor(project, editor, elements, null, REFACTORING_NAME, innerClassName, HelpID.EXTRACT_METHOD_OBJECT);
88 myElementFactory = JavaPsiFacade.getInstance(project).getElementFactory();
91 protected UsageViewDescriptor createUsageViewDescriptor(final UsageInfo[] usages) {
92 return new ExtractMethodObjectViewDescriptor(getMethod());
95 @NotNull
96 protected UsageInfo[] findUsages() {
97 final ArrayList<UsageInfo> result = new ArrayList<UsageInfo>();
98 PsiReference[] refs =
99 ReferencesSearch.search(getMethod(), GlobalSearchScope.projectScope(myProject), false).toArray(PsiReference.EMPTY_ARRAY);
100 for (PsiReference ref : refs) {
101 final PsiElement element = ref.getElement();
102 if (element != null && element.isValid()) {
103 result.add(new UsageInfo(element));
106 if (isCreateInnerClass()) {
107 final Set<PsiMethod> usedMethods = new HashSet<PsiMethod>();
108 getMethod().accept(new JavaRecursiveElementWalkingVisitor() {
109 @Override
110 public void visitMethodCallExpression(PsiMethodCallExpression expression) {
111 super.visitMethodCallExpression(expression);
112 final PsiMethod method = expression.resolveMethod();
113 if (method != null) {
114 usedMethods.add(method);
120 for (PsiMethod usedMethod : usedMethods) {
121 if (usedMethod.getModifierList().hasModifierProperty(PsiModifier.PRIVATE)) {
122 PsiMethod toMove = usedMethod;
123 for (PsiReference reference : ReferencesSearch.search(usedMethod)) {
124 if (!PsiTreeUtil.isAncestor(getMethod(), reference.getElement(), false)) {
125 toMove = null;
126 break;
129 if (toMove != null) {
130 myUsages.add(new MethodToMoveUsageInfo(toMove));
135 UsageInfo[] usageInfos = result.toArray(new UsageInfo[result.size()]);
136 return UsageViewUtil.removeDuplicatedUsages(usageInfos);
139 protected void refreshElements(final PsiElement[] elements) {}
141 protected void performRefactoring(final UsageInfo[] usages) {
142 try {
143 if (isCreateInnerClass()) {
144 myInnerClass = (PsiClass)getMethod().getContainingClass().add(myElementFactory.createClass(getInnerClassName()));
145 final boolean isStatic = copyMethodModifiers() && notHasGeneratedFields();
146 for (UsageInfo usage : usages) {
147 final PsiMethodCallExpression methodCallExpression = PsiTreeUtil.getParentOfType(usage.getElement(), PsiMethodCallExpression.class);
148 if (methodCallExpression != null) {
149 replaceMethodCallExpression(inferTypeArguments(methodCallExpression), methodCallExpression);
153 final PsiParameter[] parameters = getMethod().getParameterList().getParameters();
154 if (parameters.length > 0) {
155 createInnerClassConstructor(parameters);
156 } else if (isStatic) {
157 final PsiMethod copy = (PsiMethod)getMethod().copy();
158 copy.setName("invoke");
159 myInnerClass.add(copy);
160 if (myMultipleExitPoints) {
161 addOutputVariableFieldsWithGetters();
163 return;
165 if (myMultipleExitPoints) {
166 addOutputVariableFieldsWithGetters();
168 copyMethodWithoutParameters();
169 copyMethodTypeParameters();
170 } else {
171 for (UsageInfo usage : usages) {
172 final PsiMethodCallExpression methodCallExpression = PsiTreeUtil.getParentOfType(usage.getElement(), PsiMethodCallExpression.class);
173 if (methodCallExpression != null) {
174 methodCallExpression.replace(processMethodDeclaration( methodCallExpression.getArgumentList()));
179 catch (IncorrectOperationException e) {
180 LOG.error(e);
184 protected void moveUsedMethodsToInner() {
185 if (!myUsages.isEmpty()) {
186 final List<MemberInfo> memberInfos = new ArrayList<MemberInfo>();
187 for (MethodToMoveUsageInfo usage : myUsages) {
188 memberInfos.add(new MemberInfo((PsiMethod)usage.getElement()));
191 final MemberSelectionPanel panel = new MemberSelectionPanel("Methods to move to the extracted class", memberInfos, null);
192 DialogWrapper dlg = new DialogWrapper(myProject, false) {
194 init();
195 setTitle("Move Methods Used in Extracted Block Only");
199 @Override
200 protected JComponent createCenterPanel() {
201 return panel;
204 dlg.show();
205 if (dlg.isOK()) {
206 for (MemberInfoBase<PsiMember> memberInfo : panel.getTable().getSelectedMemberInfos()) {
207 if (memberInfo.isChecked()) {
208 myInnerClass.add(memberInfo.getMember().copy());
209 memberInfo.getMember().delete();
217 private void addOutputVariableFieldsWithGetters() throws IncorrectOperationException {
218 final Map<String, String> var2FieldNames = new HashMap<String, String>();
219 final PsiVariable[] outputVariables = myExtractProcessor.getOutputVariables();
220 for (int i = 0; i < outputVariables.length; i++) {
221 final PsiVariable var = outputVariables[i];
222 final PsiField outputField = myOutputFields[i];
223 final String name = getPureName(var);
224 LOG.assertTrue(name != null);
225 if (outputField != null) {
226 var2FieldNames.put(var.getName(), outputField.getName());
227 myInnerClass.add(outputField);
229 final PsiField field = PropertyUtil.findPropertyField(myProject, myInnerClass, name, false);
230 LOG.assertTrue(field != null, "i:" + i + "; output variables: " + Arrays.toString(outputVariables) + "; parameters: " + Arrays.toString(getMethod().getParameterList().getParameters()) + "; output field: " + outputField );
231 myInnerClass.add(PropertyUtil.generateGetterPrototype(field));
234 PsiParameter[] params = getMethod().getParameterList().getParameters();
235 ParameterInfoImpl[] infos = new ParameterInfoImpl[params.length];
236 for (int i = 0; i < params.length; i++) {
237 PsiParameter param = params[i];
238 infos[i] = new ParameterInfoImpl(i, param.getName(), param.getType());
240 ChangeSignatureProcessor cp = new ChangeSignatureProcessor(myProject, getMethod(), false, null, getMethod().getName(),
241 new PsiImmediateClassType(myInnerClass, PsiSubstitutor.EMPTY), infos);
242 cp.run();
243 final PsiCodeBlock body = getMethod().getBody();
244 LOG.assertTrue(body != null);
245 final List<PsiLocalVariable> vars = new ArrayList<PsiLocalVariable>();
246 final Map<PsiElement, PsiElement> replacementMap = new LinkedHashMap<PsiElement, PsiElement>();
247 body.accept(new JavaRecursiveElementWalkingVisitor() {
248 @Override
249 public void visitReturnStatement(final PsiReturnStatement statement) {
250 super.visitReturnStatement(statement);
251 try {
252 replacementMap.put(statement, myElementFactory.createStatementFromText("return this;", statement));
254 catch (IncorrectOperationException e) {
255 LOG.error(e);
259 @Override
260 public void visitDeclarationStatement(final PsiDeclarationStatement statement) {
261 super.visitDeclarationStatement(statement);
262 final PsiElement[] declaredElements = statement.getDeclaredElements();//todo
263 for (PsiElement declaredElement : declaredElements) {
264 if (declaredElement instanceof PsiVariable) {
265 for (PsiVariable variable : outputVariables) {
266 PsiLocalVariable var = (PsiLocalVariable)declaredElement;
267 if (Comparing.strEqual(var.getName(), variable.getName())) {
268 final PsiExpression initializer = var.getInitializer();
269 if (initializer == null) {
270 replacementMap.put(statement, null);
272 else {
273 replacementMap.put(var, var);
281 @Override
282 public void visitReferenceExpression(final PsiReferenceExpression expression) {
283 super.visitReferenceExpression(expression);
284 final PsiElement resolved = expression.resolve();
285 if (resolved instanceof PsiLocalVariable) {
286 final String var = ((PsiLocalVariable)resolved).getName();
287 for (PsiVariable variable : outputVariables) {
288 if (Comparing.strEqual(variable.getName(), var)) {
289 vars.add((PsiLocalVariable)resolved);
290 break;
297 for (PsiLocalVariable var : vars) {
298 final String fieldName = var2FieldNames.get(var.getName());
299 for (PsiReference reference : ReferencesSearch.search(var)) {
300 reference.handleElementRename(fieldName);
304 for (PsiElement statement : replacementMap.keySet()) {
305 final PsiElement replacement = replacementMap.get(statement);
306 if (replacement != null) {
307 if (statement instanceof PsiLocalVariable) {
308 final PsiLocalVariable variable = (PsiLocalVariable)statement;
309 variable.normalizeDeclaration();
310 final PsiExpression initializer = variable.getInitializer();
311 LOG.assertTrue(initializer != null);
312 final PsiStatement assignmentStatement = myElementFactory.createStatementFromText(var2FieldNames.get(variable.getName()) + " = " + initializer.getText() + ";", statement);
313 final PsiDeclarationStatement declaration = PsiTreeUtil.getParentOfType(statement, PsiDeclarationStatement.class);
314 LOG.assertTrue(declaration != null);
315 declaration.replace(assignmentStatement);
316 } else {
317 statement.replace(replacement);
319 } else {
320 statement.delete();
325 private String getPureName(PsiVariable var) {
326 final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(myProject);
327 return var instanceof PsiLocalVariable
328 ? styleManager.variableNameToPropertyName(var.getName(), VariableKind.LOCAL_VARIABLE) : styleManager.variableNameToPropertyName(var.getName(), VariableKind.PARAMETER);
331 public PsiExpression processMethodDeclaration( PsiExpressionList expressionList) throws IncorrectOperationException {
332 if (isCreateInnerClass()) {
333 final String typeArguments = getMethod().hasTypeParameters() ? "<" + StringUtil.join(Arrays.asList(getMethod().getTypeParameters()),
334 new Function<PsiTypeParameter, String>() {
335 public String fun(final PsiTypeParameter typeParameter) {
336 final String typeParameterName =
337 typeParameter.getName();
338 LOG.assertTrue(typeParameterName != null);
339 return typeParameterName;
341 }, ", ") + ">" : "";
342 final PsiMethodCallExpression methodCallExpression =
343 (PsiMethodCallExpression)myElementFactory.createExpressionFromText("invoke" + expressionList.getText(), null);
344 return replaceMethodCallExpression(typeArguments, methodCallExpression);
346 else {
347 final String paramsDeclaration = getMethod().getParameterList().getText();
348 final PsiType returnType = getMethod().getReturnType();
349 LOG.assertTrue(returnType != null);
351 final PsiCodeBlock methodBody = getMethod().getBody();
352 LOG.assertTrue(methodBody != null);
353 return myElementFactory.createExpressionFromText("new Object(){ \n" +
354 "private " +
355 returnType.getPresentableText() +
356 " " + myInnerClassName +
357 paramsDeclaration +
358 methodBody.getText() +
359 "}." + myInnerClassName +
360 expressionList.getText(), null);
365 private PsiMethodCallExpression replaceMethodCallExpression(final String inferredTypeArguments,
366 final PsiMethodCallExpression methodCallExpression)
367 throws IncorrectOperationException {
368 @NonNls final String staticqualifier =
369 getMethod().hasModifierProperty(PsiModifier.STATIC) && notHasGeneratedFields() ? getInnerClassName() : null;
370 @NonNls String newReplacement;
371 final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
372 final PsiExpressionList argumentList = methodCallExpression.getArgumentList();
373 if (staticqualifier != null) {
374 newReplacement = argumentList.getExpressions().length > 0
375 ? "new " + staticqualifier + inferredTypeArguments + argumentList.getText() + "."
376 : staticqualifier + ".";
377 } else {
378 final PsiExpression qualifierExpression = methodExpression.getQualifierExpression();
379 final String qualifier = qualifierExpression != null ? qualifierExpression.getText() + "." : "";
380 newReplacement = qualifier + "new " + getInnerClassName() + inferredTypeArguments + argumentList.getText()+ ".";
382 return (PsiMethodCallExpression)methodCallExpression.replace(myElementFactory.createExpressionFromText(newReplacement + "invoke()", null));
385 @NotNull
386 private String inferTypeArguments(final PsiMethodCallExpression methodCallExpression) {
387 final PsiReferenceParameterList list = methodCallExpression.getMethodExpression().getParameterList();
389 if (list != null && list.getTypeArguments().length > 0) {
390 return list.getText();
392 final PsiTypeParameter[] methodTypeParameters = getMethod().getTypeParameters();
393 if (methodTypeParameters.length > 0) {
394 List<String> typeSignature = new ArrayList<String>();
395 final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(getMethod().getProject()).getResolveHelper();
396 for (final PsiTypeParameter typeParameter : methodTypeParameters) {
397 final PsiType type = resolveHelper.inferTypeForMethodTypeParameter(typeParameter, getMethod().getParameterList().getParameters(),
398 methodCallExpression.getArgumentList().getExpressions(),
399 PsiSubstitutor.EMPTY, methodCallExpression, false);
400 if (type == null || PsiType.NULL.equals(type)) {
401 return "";
403 typeSignature.add(type.getPresentableText());
405 return "<" + StringUtil.join(typeSignature, ", ") + ">";
408 return "";
411 protected String getCommandName() {
412 return REFACTORING_NAME;
416 private boolean copyMethodModifiers() throws IncorrectOperationException {
417 final PsiModifierList methodModifierList = getMethod().getModifierList();
419 final PsiModifierList innerClassModifierList = myInnerClass.getModifierList();
420 LOG.assertTrue(innerClassModifierList != null);
421 innerClassModifierList.setModifierProperty(VisibilityUtil.getVisibilityModifier(methodModifierList), true);
422 final boolean isStatic = methodModifierList.hasModifierProperty(PsiModifier.STATIC);
423 innerClassModifierList.setModifierProperty(PsiModifier.STATIC, isStatic);
424 return isStatic;
427 private void copyMethodTypeParameters() throws IncorrectOperationException {
428 final PsiTypeParameterList typeParameterList = myInnerClass.getTypeParameterList();
429 LOG.assertTrue(typeParameterList != null);
431 for (PsiTypeParameter parameter : getMethod().getTypeParameters()) {
432 typeParameterList.add(parameter);
436 private void copyMethodWithoutParameters() throws IncorrectOperationException {
437 final PsiMethod newMethod = myElementFactory.createMethod("invoke", getMethod().getReturnType());
438 newMethod.getThrowsList().replace(getMethod().getThrowsList());
440 final PsiCodeBlock replacedMethodBody = newMethod.getBody();
441 LOG.assertTrue(replacedMethodBody != null);
442 final PsiCodeBlock methodBody = getMethod().getBody();
443 LOG.assertTrue(methodBody != null);
444 replacedMethodBody.replace(methodBody);
445 PsiUtil.setModifierProperty(newMethod, PsiModifier.STATIC, myInnerClass.hasModifierProperty(PsiModifier.STATIC) && notHasGeneratedFields());
446 myInnerMethod = (PsiMethod)myInnerClass.add(newMethod);
449 private boolean notHasGeneratedFields() {
450 return !myMultipleExitPoints && getMethod().getParameterList().getParametersCount() == 0;
453 private void createInnerClassConstructor(final PsiParameter[] parameters) throws IncorrectOperationException {
454 final PsiMethod constructor = myElementFactory.createConstructor();
455 final PsiParameterList parameterList = constructor.getParameterList();
456 for (PsiParameter parameter : parameters) {
457 final PsiModifierList parameterModifierList = parameter.getModifierList();
458 LOG.assertTrue(parameterModifierList != null);
459 final String parameterName = parameter.getName();
460 LOG.assertTrue(parameterName != null);
461 PsiParameter parm = myElementFactory.createParameter(parameterName, parameter.getType());
462 if (CodeStyleSettingsManager.getSettings(myProject).GENERATE_FINAL_PARAMETERS) {
463 final PsiModifierList modifierList = parm.getModifierList();
464 LOG.assertTrue(modifierList != null);
465 modifierList.setModifierProperty(PsiModifier.FINAL, true);
467 parameterList.add(parm);
469 final PsiField field = createField(parm, constructor, parameterModifierList.hasModifierProperty(PsiModifier.FINAL));
470 for (PsiReference reference : ReferencesSearch.search(parameter)) {
471 reference.handleElementRename(field.getName());
474 myInnerClass.add(constructor);
477 private PsiField createField(PsiParameter parameter, PsiMethod constructor, boolean isFinal) {
478 final String parameterName = parameter.getName();
479 PsiType type = parameter.getType();
480 if (type instanceof PsiEllipsisType) type = ((PsiEllipsisType)type).toArrayType();
481 try {
482 final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(getMethod().getProject());
483 final String fieldName = styleManager.suggestVariableName(VariableKind.FIELD, styleManager.variableNameToPropertyName(parameterName, VariableKind.PARAMETER), null, type).names[0];
484 PsiField field = myElementFactory.createField(fieldName, type);
486 final PsiModifierList modifierList = field.getModifierList();
487 LOG.assertTrue(modifierList != null);
488 if (AnnotationUtil.isAnnotated(parameter, AnnotationUtil.NULLABLE, false)) {
489 modifierList.addAfter(myElementFactory.createAnnotationFromText("@" + AnnotationUtil.NULLABLE, field), null);
491 modifierList.setModifierProperty(PsiModifier.FINAL, isFinal);
493 final PsiCodeBlock methodBody = constructor.getBody();
495 LOG.assertTrue(methodBody != null);
497 @NonNls final String stmtText;
498 if (Comparing.strEqual(parameterName, fieldName)) {
499 stmtText = "this." + fieldName + " = " + parameterName + ";";
500 } else {
501 stmtText = fieldName + " = " + parameterName + ";";
503 PsiStatement assignmentStmt = myElementFactory.createStatementFromText(stmtText, methodBody);
504 assignmentStmt = (PsiStatement)CodeStyleManager.getInstance(constructor.getProject()).reformat(assignmentStmt);
505 methodBody.add(assignmentStmt);
507 field = (PsiField)myInnerClass.add(field);
508 return field;
510 catch (IncorrectOperationException e) {
511 LOG.error(e);
513 return null;
516 protected void changeInstanceAccess(final Project project)
517 throws IncorrectOperationException {
518 if (myMadeStatic) {
519 PsiReference[] refs =
520 ReferencesSearch.search(myInnerMethod, GlobalSearchScope.projectScope(project), false).toArray(PsiReference.EMPTY_ARRAY);
521 for (PsiReference ref : refs) {
522 final PsiElement element = ref.getElement();
523 final PsiMethodCallExpression callExpression = PsiTreeUtil.getParentOfType(element, PsiMethodCallExpression.class);
524 if (callExpression != null) {
525 replaceMethodCallExpression(inferTypeArguments(callExpression), callExpression);
531 public PsiMethod getMethod() {
532 return myExtractProcessor.getExtractedMethod();
535 public String getInnerClassName() {
536 return myInnerClassName;
539 public void setCreateInnerClass(final boolean createInnerClass) {
540 myCreateInnerClass = createInnerClass;
543 public boolean isCreateInnerClass() {
544 return myCreateInnerClass;
548 public MyExtractMethodProcessor getExtractProcessor() {
549 return myExtractProcessor;
552 public class MyExtractMethodProcessor extends ExtractMethodProcessor {
554 public MyExtractMethodProcessor(Project project,
555 Editor editor,
556 PsiElement[] elements,
557 PsiType forcedReturnType,
558 String refactoringName,
559 String initialMethodName,
560 String helpId) {
561 super(project, editor, elements, forcedReturnType, refactoringName, initialMethodName, helpId);
565 @Override
566 protected void apply(final AbstractExtractDialog dialog) {
567 super.apply(dialog);
568 myCreateInnerClass = ((ExtractMethodObjectDialog)dialog).createInnerClass();
569 myInnerClassName = myCreateInnerClass ? StringUtil.capitalize(dialog.getChosenMethodName()) : dialog.getChosenMethodName();
572 @Override
573 protected AbstractExtractDialog createExtractMethodDialog(final boolean direct) {
574 return new ExtractMethodObjectDialog(myProject, myTargetClass, myInputVariables, myReturnType, myTypeParameterList,
575 myThrownExceptions, myStatic, myCanBeStatic, myElements, myMultipleExitPoints);
578 @Override
579 protected boolean checkOutputVariablesCount() {
580 myMultipleExitPoints = super.checkOutputVariablesCount();
581 myOutputFields = new PsiField[myOutputVariables.length];
582 for (int i = 0; i < myOutputVariables.length; i++) {
583 PsiVariable variable = myOutputVariables[i];
584 if (!myInputVariables.contains(variable)) { //one field creation
585 final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(myProject);
586 final String fieldName =
587 styleManager.suggestVariableName(VariableKind.FIELD, getPureName(variable), null, variable.getType()).names[0];
588 try {
589 myOutputFields[i] = myElementFactory.createField(fieldName, variable.getType());
591 catch (IncorrectOperationException e) {
592 LOG.error(e);
596 return !myCreateInnerClass && myMultipleExitPoints;
599 @Override
600 public PsiElement processMatch(final Match match) throws IncorrectOperationException {
601 final boolean makeStatic = myInnerMethod != null &&
602 RefactoringUtil.isInStaticContext(match.getMatchStart(), getExtractedMethod().getContainingClass());
603 final PsiElement element = super.processMatch(match);
604 if (makeStatic) {
605 myMadeStatic = true;
606 final PsiModifierList modifierList = myInnerMethod.getContainingClass().getModifierList();
607 LOG.assertTrue(modifierList != null);
608 modifierList.setModifierProperty(PsiModifier.STATIC, true);
609 PsiUtil.setModifierProperty(myInnerMethod, PsiModifier.STATIC, true);
611 PsiMethodCallExpression methodCallExpression = null;
612 if (element instanceof PsiMethodCallExpression) {
613 methodCallExpression = (PsiMethodCallExpression)element;
615 else if (element instanceof PsiExpressionStatement) {
616 final PsiExpression expression = ((PsiExpressionStatement)element).getExpression();
617 if (expression instanceof PsiMethodCallExpression) {
618 methodCallExpression = (PsiMethodCallExpression)expression;
620 else if (expression instanceof PsiAssignmentExpression) {
621 final PsiExpression psiExpression = ((PsiAssignmentExpression)expression).getRExpression();
622 if (psiExpression instanceof PsiMethodCallExpression) {
623 methodCallExpression = (PsiMethodCallExpression)psiExpression;
626 } else if (element instanceof PsiDeclarationStatement) {
627 final PsiElement[] declaredElements = ((PsiDeclarationStatement)element).getDeclaredElements();
628 for (PsiElement declaredElement : declaredElements) {
629 if (declaredElement instanceof PsiLocalVariable) {
630 final PsiExpression initializer = ((PsiLocalVariable)declaredElement).getInitializer();
631 if (initializer instanceof PsiMethodCallExpression) {
632 methodCallExpression = (PsiMethodCallExpression)initializer;
633 break;
638 if (methodCallExpression == null) return element;
640 PsiExpression expression = processMethodDeclaration(methodCallExpression.getArgumentList());
642 return methodCallExpression.replace(expression);
645 public PsiVariable[] getOutputVariables() {
646 return myOutputVariables;
649 @Override
650 protected void declareNecessaryVariablesAfterCall(final PsiVariable outputVariable) throws IncorrectOperationException {
651 if (myMultipleExitPoints) {
652 final String object = StringUtil.decapitalize(myInnerClassName);
653 final PsiStatement methodCallStatement = PsiTreeUtil.getParentOfType(getMethodCall(), PsiStatement.class);
654 LOG.assertTrue(methodCallStatement != null);
655 methodCallStatement.replace(
656 myElementFactory.createStatementFromText(myInnerClassName + " " + object + " = " + getMethodCall().getText() + ";", myInnerMethod));
658 final List<PsiVariable> usedVariables = myControlFlowWrapper.getUsedVariables();
659 Collection<ControlFlowUtil.VariableInfo> reassigned = myControlFlowWrapper.getInitializedTwice();
660 for (PsiVariable variable : usedVariables) {
661 String name = variable.getName();
662 LOG.assertTrue(name != null);
663 PsiStatement st = null;
664 if (isDeclaredInside(variable)) {
665 st = myElementFactory.createStatementFromText(
666 variable.getType().getCanonicalText() + " " + name + " = " + object + "." + PropertyUtil.suggestGetterName(getPureName(variable), variable.getType()) + "();",
667 myInnerMethod);
668 if (reassigned.contains(new ControlFlowUtil.VariableInfo(variable, null))) {
669 final PsiElement[] psiElements = ((PsiDeclarationStatement)st).getDeclaredElements();
670 assert psiElements.length > 0;
671 PsiVariable var = (PsiVariable)psiElements[0];
672 PsiUtil.setModifierProperty(var, PsiModifier.FINAL, false);
675 else {
676 if (ArrayUtil.find(myOutputVariables, variable) != -1) {
677 st = myElementFactory.createStatementFromText(name + " = " + object + "." + PropertyUtil.suggestGetterName(getPureName(variable), variable.getType()) + "();", myInnerMethod);
680 if (st != null) {
681 addToMethodCallLocation(st);
685 else {
686 super.declareNecessaryVariablesAfterCall(outputVariable);