class members refactoring refactoring
[fedora-idea.git] / refactoring / impl / com / intellij / refactoring / extractMethodObject / ExtractMethodObjectProcessor.java
blobe4d3965c177a6d247a0e2504f741055f8b7b61fe
1 /*
2 * User: anna
3 * Date: 06-May-2008
4 */
5 package com.intellij.refactoring.extractMethodObject;
7 import com.intellij.codeInsight.AnnotationUtil;
8 import com.intellij.openapi.diagnostic.Logger;
9 import com.intellij.openapi.editor.Editor;
10 import com.intellij.openapi.project.Project;
11 import com.intellij.openapi.ui.DialogWrapper;
12 import com.intellij.openapi.util.Comparing;
13 import com.intellij.openapi.util.text.StringUtil;
14 import com.intellij.psi.*;
15 import com.intellij.psi.codeStyle.CodeStyleManager;
16 import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
17 import com.intellij.psi.codeStyle.JavaCodeStyleManager;
18 import com.intellij.psi.codeStyle.VariableKind;
19 import com.intellij.psi.controlFlow.ControlFlowUtil;
20 import com.intellij.psi.impl.source.PsiImmediateClassType;
21 import com.intellij.psi.search.GlobalSearchScope;
22 import com.intellij.psi.search.searches.ReferencesSearch;
23 import com.intellij.psi.util.PropertyUtil;
24 import com.intellij.psi.util.PsiTreeUtil;
25 import com.intellij.psi.util.PsiUtil;
26 import com.intellij.refactoring.BaseRefactoringProcessor;
27 import com.intellij.refactoring.HelpID;
28 import com.intellij.refactoring.classMembers.MemberInfoBase;
29 import com.intellij.refactoring.changeSignature.ChangeSignatureProcessor;
30 import com.intellij.refactoring.changeSignature.ParameterInfoImpl;
31 import com.intellij.refactoring.extractMethod.AbstractExtractDialog;
32 import com.intellij.refactoring.extractMethod.ExtractMethodProcessor;
33 import com.intellij.refactoring.ui.MemberSelectionPanel;
34 import com.intellij.refactoring.util.RefactoringUtil;
35 import com.intellij.refactoring.util.VisibilityUtil;
36 import com.intellij.refactoring.util.classMembers.MemberInfo;
37 import com.intellij.refactoring.util.duplicates.Match;
38 import com.intellij.usageView.UsageInfo;
39 import com.intellij.usageView.UsageViewDescriptor;
40 import com.intellij.usageView.UsageViewUtil;
41 import com.intellij.util.ArrayUtil;
42 import com.intellij.util.Function;
43 import com.intellij.util.IncorrectOperationException;
44 import org.jetbrains.annotations.NonNls;
45 import org.jetbrains.annotations.NotNull;
47 import javax.swing.*;
48 import java.util.*;
50 public class ExtractMethodObjectProcessor extends BaseRefactoringProcessor {
51 private static final Logger LOG = Logger.getInstance("#" + com.intellij.refactoring.extractMethodObject.ExtractMethodObjectProcessor.class.getName());
52 @NonNls public static final String REFACTORING_NAME = "Extract Method Object";
54 private final PsiElementFactory myElementFactory;
56 private final MyExtractMethodProcessor myExtractProcessor;
57 private boolean myCreateInnerClass = true;
58 private String myInnerClassName;
60 private boolean myMultipleExitPoints;
61 private PsiField[] myOutputFields;
63 private PsiMethod myInnerMethod;
64 private boolean myMadeStatic = false;
65 private final Set<MethodToMoveUsageInfo> myUsages = new HashSet<MethodToMoveUsageInfo>();
66 private PsiClass myInnerClass;
68 public ExtractMethodObjectProcessor(Project project, Editor editor, PsiElement[] elements, final String innerClassName) {
69 super(project);
70 myInnerClassName = innerClassName;
71 myExtractProcessor = new MyExtractMethodProcessor(project, editor, elements, null, REFACTORING_NAME, innerClassName, HelpID.EXTRACT_METHOD_OBJECT);
72 myElementFactory = JavaPsiFacade.getInstance(project).getElementFactory();
75 protected UsageViewDescriptor createUsageViewDescriptor(final UsageInfo[] usages) {
76 return new ExtractMethodObjectViewDescriptor(getMethod());
79 @NotNull
80 protected UsageInfo[] findUsages() {
81 final ArrayList<UsageInfo> result = new ArrayList<UsageInfo>();
82 PsiReference[] refs =
83 ReferencesSearch.search(getMethod(), GlobalSearchScope.projectScope(myProject), false).toArray(PsiReference.EMPTY_ARRAY);
84 for (PsiReference ref : refs) {
85 final PsiElement element = ref.getElement();
86 if (element != null && element.isValid()) {
87 result.add(new UsageInfo(element));
90 if (isCreateInnerClass()) {
91 final Set<PsiMethod> usedMethods = new HashSet<PsiMethod>();
92 getMethod().accept(new JavaRecursiveElementWalkingVisitor() {
93 @Override
94 public void visitMethodCallExpression(PsiMethodCallExpression expression) {
95 super.visitMethodCallExpression(expression);
96 final PsiMethod method = expression.resolveMethod();
97 if (method != null) {
98 usedMethods.add(method);
104 for (PsiMethod usedMethod : usedMethods) {
105 if (usedMethod.getModifierList().hasModifierProperty(PsiModifier.PRIVATE)) {
106 PsiMethod toMove = usedMethod;
107 for (PsiReference reference : ReferencesSearch.search(usedMethod)) {
108 if (!PsiTreeUtil.isAncestor(getMethod(), reference.getElement(), false)) {
109 toMove = null;
110 break;
113 if (toMove != null) {
114 myUsages.add(new MethodToMoveUsageInfo(toMove));
119 UsageInfo[] usageInfos = result.toArray(new UsageInfo[result.size()]);
120 return UsageViewUtil.removeDuplicatedUsages(usageInfos);
123 protected void refreshElements(final PsiElement[] elements) {}
125 protected void performRefactoring(final UsageInfo[] usages) {
126 try {
127 if (isCreateInnerClass()) {
128 myInnerClass = (PsiClass)getMethod().getContainingClass().add(myElementFactory.createClass(getInnerClassName()));
129 final boolean isStatic = copyMethodModifiers() && notHasGeneratedFields();
130 for (UsageInfo usage : usages) {
131 final PsiMethodCallExpression methodCallExpression = PsiTreeUtil.getParentOfType(usage.getElement(), PsiMethodCallExpression.class);
132 if (methodCallExpression != null) {
133 replaceMethodCallExpression(inferTypeArguments(methodCallExpression), methodCallExpression);
137 final PsiParameter[] parameters = getMethod().getParameterList().getParameters();
138 if (parameters.length > 0) {
139 createInnerClassConstructor(parameters);
140 } else if (isStatic) {
141 final PsiMethod copy = (PsiMethod)getMethod().copy();
142 copy.setName("invoke");
143 myInnerClass.add(copy);
144 if (myMultipleExitPoints) {
145 addOutputVariableFieldsWithGetters();
147 return;
149 if (myMultipleExitPoints) {
150 addOutputVariableFieldsWithGetters();
152 copyMethodWithoutParameters();
153 copyMethodTypeParameters();
154 } else {
155 for (UsageInfo usage : usages) {
156 final PsiMethodCallExpression methodCallExpression = PsiTreeUtil.getParentOfType(usage.getElement(), PsiMethodCallExpression.class);
157 if (methodCallExpression != null) {
158 methodCallExpression.replace(processMethodDeclaration( methodCallExpression.getArgumentList()));
163 catch (IncorrectOperationException e) {
164 LOG.error(e);
168 protected void moveUsedMethodsToInner() {
169 if (!myUsages.isEmpty()) {
170 final List<MemberInfo> memberInfos = new ArrayList<MemberInfo>();
171 for (MethodToMoveUsageInfo usage : myUsages) {
172 memberInfos.add(new MemberInfo((PsiMethod)usage.getElement()));
175 final MemberSelectionPanel panel = new MemberSelectionPanel("Methods to move to the extracted class", memberInfos, null);
176 DialogWrapper dlg = new DialogWrapper(myProject, false) {
178 init();
179 setTitle("Move Methods Used in Extracted Block Only");
183 @Override
184 protected JComponent createCenterPanel() {
185 return panel;
188 dlg.show();
189 if (dlg.isOK()) {
190 for (MemberInfoBase<PsiMember> memberInfo : panel.getTable().getSelectedMemberInfos()) {
191 if (memberInfo.isChecked()) {
192 myInnerClass.add(memberInfo.getMember().copy());
193 memberInfo.getMember().delete();
201 private void addOutputVariableFieldsWithGetters() throws IncorrectOperationException {
202 final Map<String, String> var2FieldNames = new HashMap<String, String>();
203 final PsiVariable[] outputVariables = myExtractProcessor.getOutputVariables();
204 for (int i = 0; i < outputVariables.length; i++) {
205 final PsiVariable var = outputVariables[i];
206 final PsiField outputField = myOutputFields[i];
207 final String name = getPureName(var);
208 LOG.assertTrue(name != null);
209 if (outputField != null) {
210 var2FieldNames.put(var.getName(), outputField.getName());
211 myInnerClass.add(outputField);
213 final PsiField field = PropertyUtil.findPropertyField(myProject, myInnerClass, name, false);
214 LOG.assertTrue(field != null, "i:" + i + "; output variables: " + Arrays.toString(outputVariables) + "; parameters: " + Arrays.toString(getMethod().getParameterList().getParameters()) + "; output field: " + outputField );
215 myInnerClass.add(PropertyUtil.generateGetterPrototype(field));
218 PsiParameter[] params = getMethod().getParameterList().getParameters();
219 ParameterInfoImpl[] infos = new ParameterInfoImpl[params.length];
220 for (int i = 0; i < params.length; i++) {
221 PsiParameter param = params[i];
222 infos[i] = new ParameterInfoImpl(i, param.getName(), param.getType());
224 ChangeSignatureProcessor cp = new ChangeSignatureProcessor(myProject, getMethod(), false, null, getMethod().getName(),
225 new PsiImmediateClassType(myInnerClass, PsiSubstitutor.EMPTY), infos);
226 cp.run();
227 final PsiCodeBlock body = getMethod().getBody();
228 LOG.assertTrue(body != null);
229 final List<PsiLocalVariable> vars = new ArrayList<PsiLocalVariable>();
230 final Map<PsiElement, PsiElement> replacementMap = new LinkedHashMap<PsiElement, PsiElement>();
231 body.accept(new JavaRecursiveElementWalkingVisitor() {
232 @Override
233 public void visitReturnStatement(final PsiReturnStatement statement) {
234 super.visitReturnStatement(statement);
235 try {
236 replacementMap.put(statement, myElementFactory.createStatementFromText("return this;", statement));
238 catch (IncorrectOperationException e) {
239 LOG.error(e);
243 @Override
244 public void visitDeclarationStatement(final PsiDeclarationStatement statement) {
245 super.visitDeclarationStatement(statement);
246 final PsiElement[] declaredElements = statement.getDeclaredElements();//todo
247 for (PsiElement declaredElement : declaredElements) {
248 if (declaredElement instanceof PsiVariable) {
249 for (PsiVariable variable : outputVariables) {
250 PsiLocalVariable var = (PsiLocalVariable)declaredElement;
251 if (Comparing.strEqual(var.getName(), variable.getName())) {
252 final PsiExpression initializer = var.getInitializer();
253 if (initializer == null) {
254 replacementMap.put(statement, null);
256 else {
257 replacementMap.put(var, var);
265 @Override
266 public void visitReferenceExpression(final PsiReferenceExpression expression) {
267 super.visitReferenceExpression(expression);
268 final PsiElement resolved = expression.resolve();
269 if (resolved instanceof PsiLocalVariable) {
270 final String var = ((PsiLocalVariable)resolved).getName();
271 for (PsiVariable variable : outputVariables) {
272 if (Comparing.strEqual(variable.getName(), var)) {
273 vars.add((PsiLocalVariable)resolved);
274 break;
281 for (PsiLocalVariable var : vars) {
282 final String fieldName = var2FieldNames.get(var.getName());
283 for (PsiReference reference : ReferencesSearch.search(var)) {
284 reference.handleElementRename(fieldName);
288 for (PsiElement statement : replacementMap.keySet()) {
289 final PsiElement replacement = replacementMap.get(statement);
290 if (replacement != null) {
291 if (statement instanceof PsiLocalVariable) {
292 final PsiLocalVariable variable = (PsiLocalVariable)statement;
293 variable.normalizeDeclaration();
294 final PsiExpression initializer = variable.getInitializer();
295 LOG.assertTrue(initializer != null);
296 final PsiStatement assignmentStatement = myElementFactory.createStatementFromText(var2FieldNames.get(variable.getName()) + " = " + initializer.getText() + ";", statement);
297 final PsiDeclarationStatement declaration = PsiTreeUtil.getParentOfType(statement, PsiDeclarationStatement.class);
298 LOG.assertTrue(declaration != null);
299 declaration.replace(assignmentStatement);
300 } else {
301 statement.replace(replacement);
303 } else {
304 statement.delete();
309 private String getPureName(PsiVariable var) {
310 final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(myProject);
311 return var instanceof PsiLocalVariable
312 ? styleManager.variableNameToPropertyName(var.getName(), VariableKind.LOCAL_VARIABLE) : styleManager.variableNameToPropertyName(var.getName(), VariableKind.PARAMETER);
315 public PsiExpression processMethodDeclaration( PsiExpressionList expressionList) throws IncorrectOperationException {
316 if (isCreateInnerClass()) {
317 final String typeArguments = getMethod().hasTypeParameters() ? "<" + StringUtil.join(Arrays.asList(getMethod().getTypeParameters()),
318 new Function<PsiTypeParameter, String>() {
319 public String fun(final PsiTypeParameter typeParameter) {
320 final String typeParameterName =
321 typeParameter.getName();
322 LOG.assertTrue(typeParameterName != null);
323 return typeParameterName;
325 }, ", ") + ">" : "";
326 final PsiMethodCallExpression methodCallExpression =
327 (PsiMethodCallExpression)myElementFactory.createExpressionFromText("invoke" + expressionList.getText(), null);
328 return replaceMethodCallExpression(typeArguments, methodCallExpression);
330 else {
331 final String paramsDeclaration = getMethod().getParameterList().getText();
332 final PsiType returnType = getMethod().getReturnType();
333 LOG.assertTrue(returnType != null);
335 final PsiCodeBlock methodBody = getMethod().getBody();
336 LOG.assertTrue(methodBody != null);
337 return myElementFactory.createExpressionFromText("new Object(){ \n" +
338 "private " +
339 returnType.getPresentableText() +
340 " " + myInnerClassName +
341 paramsDeclaration +
342 methodBody.getText() +
343 "}." + myInnerClassName +
344 expressionList.getText(), null);
349 private PsiMethodCallExpression replaceMethodCallExpression(final String inferredTypeArguments,
350 final PsiMethodCallExpression methodCallExpression)
351 throws IncorrectOperationException {
352 @NonNls final String staticqualifier =
353 getMethod().hasModifierProperty(PsiModifier.STATIC) && notHasGeneratedFields() ? getInnerClassName() : null;
354 @NonNls String newReplacement;
355 final PsiReferenceExpression methodExpression = methodCallExpression.getMethodExpression();
356 final PsiExpressionList argumentList = methodCallExpression.getArgumentList();
357 if (staticqualifier != null) {
358 newReplacement = argumentList.getExpressions().length > 0
359 ? "new " + staticqualifier + inferredTypeArguments + argumentList.getText() + "."
360 : staticqualifier + ".";
361 } else {
362 final PsiExpression qualifierExpression = methodExpression.getQualifierExpression();
363 final String qualifier = qualifierExpression != null ? qualifierExpression.getText() + "." : "";
364 newReplacement = qualifier + "new " + getInnerClassName() + inferredTypeArguments + argumentList.getText()+ ".";
366 return (PsiMethodCallExpression)methodCallExpression.replace(myElementFactory.createExpressionFromText(newReplacement + "invoke()", null));
369 @NotNull
370 private String inferTypeArguments(final PsiMethodCallExpression methodCallExpression) {
371 final PsiReferenceParameterList list = methodCallExpression.getMethodExpression().getParameterList();
373 if (list != null && list.getTypeArguments().length > 0) {
374 return list.getText();
376 final PsiTypeParameter[] methodTypeParameters = getMethod().getTypeParameters();
377 if (methodTypeParameters.length > 0) {
378 List<String> typeSignature = new ArrayList<String>();
379 final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(getMethod().getProject()).getResolveHelper();
380 for (final PsiTypeParameter typeParameter : methodTypeParameters) {
381 final PsiType type = resolveHelper.inferTypeForMethodTypeParameter(typeParameter, getMethod().getParameterList().getParameters(),
382 methodCallExpression.getArgumentList().getExpressions(),
383 PsiSubstitutor.EMPTY, methodCallExpression, false);
384 if (type == null || PsiType.NULL.equals(type)) {
385 return "";
387 typeSignature.add(type.getPresentableText());
389 return "<" + StringUtil.join(typeSignature, ", ") + ">";
392 return "";
395 protected String getCommandName() {
396 return REFACTORING_NAME;
400 private boolean copyMethodModifiers() throws IncorrectOperationException {
401 final PsiModifierList methodModifierList = getMethod().getModifierList();
403 final PsiModifierList innerClassModifierList = myInnerClass.getModifierList();
404 LOG.assertTrue(innerClassModifierList != null);
405 innerClassModifierList.setModifierProperty(VisibilityUtil.getVisibilityModifier(methodModifierList), true);
406 final boolean isStatic = methodModifierList.hasModifierProperty(PsiModifier.STATIC);
407 innerClassModifierList.setModifierProperty(PsiModifier.STATIC, isStatic);
408 return isStatic;
411 private void copyMethodTypeParameters() throws IncorrectOperationException {
412 final PsiTypeParameterList typeParameterList = myInnerClass.getTypeParameterList();
413 LOG.assertTrue(typeParameterList != null);
415 for (PsiTypeParameter parameter : getMethod().getTypeParameters()) {
416 typeParameterList.add(parameter);
420 private void copyMethodWithoutParameters() throws IncorrectOperationException {
421 final PsiMethod newMethod = myElementFactory.createMethod("invoke", getMethod().getReturnType());
422 newMethod.getThrowsList().replace(getMethod().getThrowsList());
424 final PsiCodeBlock replacedMethodBody = newMethod.getBody();
425 LOG.assertTrue(replacedMethodBody != null);
426 final PsiCodeBlock methodBody = getMethod().getBody();
427 LOG.assertTrue(methodBody != null);
428 replacedMethodBody.replace(methodBody);
429 PsiUtil.setModifierProperty(newMethod, PsiModifier.STATIC, myInnerClass.hasModifierProperty(PsiModifier.STATIC) && notHasGeneratedFields());
430 myInnerMethod = (PsiMethod)myInnerClass.add(newMethod);
433 private boolean notHasGeneratedFields() {
434 return !myMultipleExitPoints && getMethod().getParameterList().getParametersCount() == 0;
437 private void createInnerClassConstructor(final PsiParameter[] parameters) throws IncorrectOperationException {
438 final PsiMethod constructor = myElementFactory.createConstructor();
439 final PsiParameterList parameterList = constructor.getParameterList();
440 for (PsiParameter parameter : parameters) {
441 final PsiModifierList parameterModifierList = parameter.getModifierList();
442 LOG.assertTrue(parameterModifierList != null);
443 final String parameterName = parameter.getName();
444 LOG.assertTrue(parameterName != null);
445 PsiParameter parm = myElementFactory.createParameter(parameterName, parameter.getType());
446 if (CodeStyleSettingsManager.getSettings(myProject).GENERATE_FINAL_PARAMETERS) {
447 final PsiModifierList modifierList = parm.getModifierList();
448 LOG.assertTrue(modifierList != null);
449 modifierList.setModifierProperty(PsiModifier.FINAL, true);
451 parameterList.add(parm);
453 final PsiField field = createField(parm, constructor, parameterModifierList.hasModifierProperty(PsiModifier.FINAL));
454 for (PsiReference reference : ReferencesSearch.search(parameter)) {
455 reference.handleElementRename(field.getName());
458 myInnerClass.add(constructor);
461 private PsiField createField(PsiParameter parameter, PsiMethod constructor, boolean isFinal) {
462 final String parameterName = parameter.getName();
463 PsiType type = parameter.getType();
464 if (type instanceof PsiEllipsisType) type = ((PsiEllipsisType)type).toArrayType();
465 try {
466 final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(getMethod().getProject());
467 final String fieldName = styleManager.suggestVariableName(VariableKind.FIELD, styleManager.variableNameToPropertyName(parameterName, VariableKind.PARAMETER), null, type).names[0];
468 PsiField field = myElementFactory.createField(fieldName, type);
470 final PsiModifierList modifierList = field.getModifierList();
471 LOG.assertTrue(modifierList != null);
472 if (AnnotationUtil.isAnnotated(parameter, AnnotationUtil.NULLABLE, false)) {
473 modifierList.addAfter(myElementFactory.createAnnotationFromText("@" + AnnotationUtil.NULLABLE, field), null);
475 modifierList.setModifierProperty(PsiModifier.FINAL, isFinal);
477 final PsiCodeBlock methodBody = constructor.getBody();
479 LOG.assertTrue(methodBody != null);
481 @NonNls final String stmtText;
482 if (Comparing.strEqual(parameterName, fieldName)) {
483 stmtText = "this." + fieldName + " = " + parameterName + ";";
484 } else {
485 stmtText = fieldName + " = " + parameterName + ";";
487 PsiStatement assignmentStmt = myElementFactory.createStatementFromText(stmtText, methodBody);
488 assignmentStmt = (PsiStatement)CodeStyleManager.getInstance(constructor.getProject()).reformat(assignmentStmt);
489 methodBody.add(assignmentStmt);
491 field = (PsiField)myInnerClass.add(field);
492 return field;
494 catch (IncorrectOperationException e) {
495 LOG.error(e);
497 return null;
500 protected void changeInstanceAccess(final Project project)
501 throws IncorrectOperationException {
502 if (myMadeStatic) {
503 PsiReference[] refs =
504 ReferencesSearch.search(myInnerMethod, GlobalSearchScope.projectScope(project), false).toArray(PsiReference.EMPTY_ARRAY);
505 for (PsiReference ref : refs) {
506 final PsiElement element = ref.getElement();
507 final PsiMethodCallExpression callExpression = PsiTreeUtil.getParentOfType(element, PsiMethodCallExpression.class);
508 if (callExpression != null) {
509 replaceMethodCallExpression(inferTypeArguments(callExpression), callExpression);
515 public PsiMethod getMethod() {
516 return myExtractProcessor.getExtractedMethod();
519 public String getInnerClassName() {
520 return myInnerClassName;
523 public void setCreateInnerClass(final boolean createInnerClass) {
524 myCreateInnerClass = createInnerClass;
527 public boolean isCreateInnerClass() {
528 return myCreateInnerClass;
532 public MyExtractMethodProcessor getExtractProcessor() {
533 return myExtractProcessor;
536 public class MyExtractMethodProcessor extends ExtractMethodProcessor {
538 public MyExtractMethodProcessor(Project project,
539 Editor editor,
540 PsiElement[] elements,
541 PsiType forcedReturnType,
542 String refactoringName,
543 String initialMethodName,
544 String helpId) {
545 super(project, editor, elements, forcedReturnType, refactoringName, initialMethodName, helpId);
549 @Override
550 protected void apply(final AbstractExtractDialog dialog) {
551 super.apply(dialog);
552 myCreateInnerClass = ((ExtractMethodObjectDialog)dialog).createInnerClass();
553 myInnerClassName = myCreateInnerClass ? StringUtil.capitalize(dialog.getChosenMethodName()) : dialog.getChosenMethodName();
556 @Override
557 protected AbstractExtractDialog createExtractMethodDialog(final boolean direct) {
558 return new ExtractMethodObjectDialog(myProject, myTargetClass, myInputVariables, myReturnType, myTypeParameterList,
559 myThrownExceptions, myStatic, myCanBeStatic, myElements, myMultipleExitPoints);
562 @Override
563 protected boolean checkOutputVariablesCount() {
564 myMultipleExitPoints = super.checkOutputVariablesCount();
565 myOutputFields = new PsiField[myOutputVariables.length];
566 for (int i = 0; i < myOutputVariables.length; i++) {
567 PsiVariable variable = myOutputVariables[i];
568 if (!myInputVariables.contains(variable)) { //one field creation
569 final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(myProject);
570 final String fieldName =
571 styleManager.suggestVariableName(VariableKind.FIELD, getPureName(variable), null, variable.getType()).names[0];
572 try {
573 myOutputFields[i] = myElementFactory.createField(fieldName, variable.getType());
575 catch (IncorrectOperationException e) {
576 LOG.error(e);
580 return !myCreateInnerClass && myMultipleExitPoints;
583 @Override
584 public PsiElement processMatch(final Match match) throws IncorrectOperationException {
585 final boolean makeStatic = myInnerMethod != null &&
586 RefactoringUtil.isInStaticContext(match.getMatchStart(), getExtractedMethod().getContainingClass());
587 final PsiElement element = super.processMatch(match);
588 if (makeStatic) {
589 myMadeStatic = true;
590 final PsiModifierList modifierList = myInnerMethod.getContainingClass().getModifierList();
591 LOG.assertTrue(modifierList != null);
592 modifierList.setModifierProperty(PsiModifier.STATIC, true);
593 PsiUtil.setModifierProperty(myInnerMethod, PsiModifier.STATIC, true);
595 PsiMethodCallExpression methodCallExpression = null;
596 if (element instanceof PsiMethodCallExpression) {
597 methodCallExpression = (PsiMethodCallExpression)element;
599 else if (element instanceof PsiExpressionStatement) {
600 final PsiExpression expression = ((PsiExpressionStatement)element).getExpression();
601 if (expression instanceof PsiMethodCallExpression) {
602 methodCallExpression = (PsiMethodCallExpression)expression;
604 else if (expression instanceof PsiAssignmentExpression) {
605 final PsiExpression psiExpression = ((PsiAssignmentExpression)expression).getRExpression();
606 if (psiExpression instanceof PsiMethodCallExpression) {
607 methodCallExpression = (PsiMethodCallExpression)psiExpression;
610 } else if (element instanceof PsiDeclarationStatement) {
611 final PsiElement[] declaredElements = ((PsiDeclarationStatement)element).getDeclaredElements();
612 for (PsiElement declaredElement : declaredElements) {
613 if (declaredElement instanceof PsiLocalVariable) {
614 final PsiExpression initializer = ((PsiLocalVariable)declaredElement).getInitializer();
615 if (initializer instanceof PsiMethodCallExpression) {
616 methodCallExpression = (PsiMethodCallExpression)initializer;
617 break;
622 if (methodCallExpression == null) return element;
624 PsiExpression expression = processMethodDeclaration(methodCallExpression.getArgumentList());
626 return methodCallExpression.replace(expression);
629 public PsiVariable[] getOutputVariables() {
630 return myOutputVariables;
633 @Override
634 protected void declareNecessaryVariablesAfterCall(final PsiVariable outputVariable) throws IncorrectOperationException {
635 if (myMultipleExitPoints) {
636 final String object = StringUtil.decapitalize(myInnerClassName);
637 final PsiStatement methodCallStatement = PsiTreeUtil.getParentOfType(getMethodCall(), PsiStatement.class);
638 LOG.assertTrue(methodCallStatement != null);
639 methodCallStatement.replace(
640 myElementFactory.createStatementFromText(myInnerClassName + " " + object + " = " + getMethodCall().getText() + ";", myInnerMethod));
642 final List<PsiVariable> usedVariables = myControlFlowWrapper.getUsedVariables();
643 Collection<ControlFlowUtil.VariableInfo> reassigned = myControlFlowWrapper.getInitializedTwice();
644 for (PsiVariable variable : usedVariables) {
645 String name = variable.getName();
646 LOG.assertTrue(name != null);
647 PsiStatement st = null;
648 if (isDeclaredInside(variable)) {
649 st = myElementFactory.createStatementFromText(
650 variable.getType().getCanonicalText() + " " + name + " = " + object + "." + PropertyUtil.suggestGetterName(getPureName(variable), variable.getType()) + "();",
651 myInnerMethod);
652 if (reassigned.contains(new ControlFlowUtil.VariableInfo(variable, null))) {
653 final PsiElement[] psiElements = ((PsiDeclarationStatement)st).getDeclaredElements();
654 assert psiElements.length > 0;
655 PsiVariable var = (PsiVariable)psiElements[0];
656 PsiUtil.setModifierProperty(var, PsiModifier.FINAL, false);
659 else {
660 if (ArrayUtil.find(myOutputVariables, variable) != -1) {
661 st = myElementFactory.createStatementFromText(name + " = " + object + "." + PropertyUtil.suggestGetterName(getPureName(variable), variable.getType()) + "();", myInnerMethod);
664 if (st != null) {
665 addToMethodCallLocation(st);
669 else {
670 super.declareNecessaryVariablesAfterCall(outputVariable);