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.
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
;
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
) {
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());
96 protected UsageInfo
[] findUsages() {
97 final ArrayList
<UsageInfo
> result
= new ArrayList
<UsageInfo
>();
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() {
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)) {
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
) {
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();
165 if (myMultipleExitPoints
) {
166 addOutputVariableFieldsWithGetters();
168 copyMethodWithoutParameters();
169 copyMethodTypeParameters();
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
) {
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) {
195 setTitle("Move Methods Used in Extracted Block Only");
200 protected JComponent
createCenterPanel() {
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
);
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() {
249 public void visitReturnStatement(final PsiReturnStatement statement
) {
250 super.visitReturnStatement(statement
);
252 replacementMap
.put(statement
, myElementFactory
.createStatementFromText("return this;", statement
));
254 catch (IncorrectOperationException e
) {
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);
273 replacementMap
.put(var
, var
);
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
);
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
);
317 statement
.replace(replacement
);
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
;
342 final PsiMethodCallExpression methodCallExpression
=
343 (PsiMethodCallExpression
)myElementFactory
.createExpressionFromText("invoke" + expressionList
.getText(), null);
344 return replaceMethodCallExpression(typeArguments
, methodCallExpression
);
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" +
355 returnType
.getPresentableText() +
356 " " + myInnerClassName
+
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
+ ".";
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));
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
)) {
403 typeSignature
.add(type
.getPresentableText());
405 return "<" + StringUtil
.join(typeSignature
, ", ") + ">";
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
);
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();
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
+ ";";
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
);
510 catch (IncorrectOperationException e
) {
516 protected void changeInstanceAccess(final Project project
)
517 throws IncorrectOperationException
{
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
,
556 PsiElement
[] elements
,
557 PsiType forcedReturnType
,
558 String refactoringName
,
559 String initialMethodName
,
561 super(project
, editor
, elements
, forcedReturnType
, refactoringName
, initialMethodName
, helpId
);
566 protected void apply(final AbstractExtractDialog dialog
) {
568 myCreateInnerClass
= ((ExtractMethodObjectDialog
)dialog
).createInnerClass();
569 myInnerClassName
= myCreateInnerClass ? StringUtil
.capitalize(dialog
.getChosenMethodName()) : dialog
.getChosenMethodName();
573 protected AbstractExtractDialog
createExtractMethodDialog(final boolean direct
) {
574 return new ExtractMethodObjectDialog(myProject
, myTargetClass
, myInputVariables
, myReturnType
, myTypeParameterList
,
575 myThrownExceptions
, myStatic
, myCanBeStatic
, myElements
, myMultipleExitPoints
);
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];
589 myOutputFields
[i
] = myElementFactory
.createField(fieldName
, variable
.getType());
591 catch (IncorrectOperationException e
) {
596 return !myCreateInnerClass
&& myMultipleExitPoints
;
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
);
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
;
638 if (methodCallExpression
== null) return element
;
640 PsiExpression expression
= processMethodDeclaration(methodCallExpression
.getArgumentList());
642 return methodCallExpression
.replace(expression
);
645 public PsiVariable
[] getOutputVariables() {
646 return myOutputVariables
;
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()) + "();",
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);
676 if (ArrayUtil
.find(myOutputVariables
, variable
) != -1) {
677 st
= myElementFactory
.createStatementFromText(name
+ " = " + object
+ "." + PropertyUtil
.suggestGetterName(getPureName(variable
), variable
.getType()) + "();", myInnerMethod
);
681 addToMethodCallLocation(st
);
686 super.declareNecessaryVariablesAfterCall(outputVariable
);