2 package com
.intellij
.refactoring
.inline
;
4 import com
.intellij
.codeInsight
.TargetElementUtil
;
5 import com
.intellij
.openapi
.editor
.Editor
;
6 import com
.intellij
.openapi
.project
.Project
;
7 import com
.intellij
.openapi
.vfs
.ReadonlyStatusHandler
;
8 import com
.intellij
.openapi
.vfs
.VirtualFile
;
9 import com
.intellij
.psi
.*;
10 import com
.intellij
.refactoring
.HelpID
;
11 import com
.intellij
.refactoring
.RefactoringBundle
;
12 import com
.intellij
.refactoring
.util
.RefactoringUtil
;
13 import com
.intellij
.refactoring
.util
.CommonRefactoringUtil
;
15 class InlineMethodHandler
{
16 private static final String REFACTORING_NAME
= RefactoringBundle
.message("inline.method.title");
18 public void invoke(final Project project
, Editor editor
, PsiMethod method
) {
19 method
= (PsiMethod
)method
.getNavigationElement();
20 if (method
.getBody() == null){
22 if (method
.hasModifierProperty(PsiModifier
.ABSTRACT
)) {
23 message
= RefactoringBundle
.message("refactoring.cannot.be.applied.to.abstract.methods", REFACTORING_NAME
);
26 message
= RefactoringBundle
.message("refactoring.cannot.be.applied.no.sources.attached", REFACTORING_NAME
);
28 CommonRefactoringUtil
.showErrorMessage(REFACTORING_NAME
, message
, HelpID
.INLINE_METHOD
, project
);
32 if (InlineMethodProcessor
.checkBadReturns(method
)) {
33 String message
= RefactoringBundle
.message("refactoring.is.not.supported.when.return.statement.interrupts.the.execution.flow", REFACTORING_NAME
);
34 CommonRefactoringUtil
.showErrorMessage(REFACTORING_NAME
, message
, HelpID
.INLINE_METHOD
, project
);
38 PsiReference reference
= editor
!= null ? TargetElementUtil
.findReference(editor
, editor
.getCaretModel().getOffset()) : null;
39 if (reference
== null && checkRecursive(method
)) {
40 String message
= RefactoringBundle
.message("refactoring.is.not.supported.for.recursive.methods", REFACTORING_NAME
);
41 CommonRefactoringUtil
.showErrorMessage(REFACTORING_NAME
, message
, HelpID
.INLINE_METHOD
, project
);
45 if (method
.isConstructor()) {
46 if (method
.isVarArgs()) {
47 String message
= RefactoringBundle
.message("refactoring.cannot.be.applied.to.vararg.constructors", REFACTORING_NAME
);
48 CommonRefactoringUtil
.showErrorMessage(REFACTORING_NAME
, message
, HelpID
.INLINE_METHOD
, project
);
51 if (!checkChainingConstructor(method
)) {
52 String message
= RefactoringBundle
.message("refactoring.cannot.be.applied.to.inline.non.chaining.constructors", REFACTORING_NAME
);
53 CommonRefactoringUtil
.showErrorMessage(REFACTORING_NAME
, message
, HelpID
.INLINE_METHOD
, project
);
56 if (reference
!= null) {
57 PsiCall constructorCall
= RefactoringUtil
.getEnclosingConstructorCall((PsiJavaCodeReferenceElement
)reference
.getElement());
58 if (constructorCall
== null || !method
.equals(constructorCall
.resolveMethod())) reference
= null;
62 if (reference
!= null && !method
.getManager().areElementsEquivalent(method
, reference
.resolve())) {
67 final boolean invokedOnReference
= reference
!= null;
68 if (!invokedOnReference
) {
69 final VirtualFile vFile
= method
.getContainingFile().getVirtualFile();
70 ReadonlyStatusHandler
.getInstance(project
).ensureFilesWritable(vFile
);
72 PsiJavaCodeReferenceElement refElement
= reference
!= null ?
(PsiJavaCodeReferenceElement
)reference
.getElement() : null;
73 InlineMethodDialog dialog
= new InlineMethodDialog(project
, method
, refElement
, editor
);
77 private static boolean checkChainingConstructor(PsiMethod constructor
) {
78 PsiCodeBlock body
= constructor
.getBody();
80 PsiStatement
[] statements
= body
.getStatements();
81 if (statements
.length
== 1 && statements
[0] instanceof PsiExpressionStatement
) {
82 PsiExpression expression
= ((PsiExpressionStatement
)statements
[0]).getExpression();
83 if (expression
instanceof PsiMethodCallExpression
) {
84 PsiReferenceExpression methodExpr
= ((PsiMethodCallExpression
)expression
).getMethodExpression();
85 if ("this".equals(methodExpr
.getReferenceName())) {
86 PsiElement resolved
= methodExpr
.resolve();
87 return resolved
instanceof PsiMethod
&& ((PsiMethod
)resolved
).isConstructor(); //delegated via "this" call
95 public static boolean checkRecursive(PsiMethod method
) {
96 return checkCalls(method
.getBody(), method
);
99 private static boolean checkCalls(PsiElement scope
, PsiMethod method
) {
100 if (scope
instanceof PsiMethodCallExpression
){
101 PsiMethod refMethod
= (PsiMethod
)((PsiMethodCallExpression
)scope
).getMethodExpression().resolve();
102 if (method
.equals(refMethod
)) return true;
105 for(PsiElement child
= scope
.getFirstChild(); child
!= null; child
= child
.getNextSibling()){
106 if (checkCalls(child
, method
)) return true;