0a40702708d580392990f7b4e2d5aaa22d439ef5
[idea/community.git] / java / java-impl / src / com / intellij / refactoring / changeSignature / JavaChangeSignatureHandler.java
1 /*
2  * Copyright 2000-2010 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 package com.intellij.refactoring.changeSignature;
17
18 import com.intellij.codeInsight.TargetElementUtil;
19 import com.intellij.ide.util.SuperMethodWarningUtil;
20 import com.intellij.openapi.actionSystem.DataContext;
21 import com.intellij.openapi.actionSystem.LangDataKeys;
22 import com.intellij.openapi.actionSystem.PlatformDataKeys;
23 import com.intellij.openapi.editor.Editor;
24 import com.intellij.openapi.editor.ScrollType;
25 import com.intellij.openapi.project.Project;
26 import com.intellij.psi.*;
27 import com.intellij.psi.util.PsiTreeUtil;
28 import com.intellij.refactoring.HelpID;
29 import com.intellij.refactoring.RefactoringBundle;
30 import com.intellij.refactoring.changeClassSignature.ChangeClassSignatureDialog;
31 import com.intellij.refactoring.util.CommonRefactoringUtil;
32 import org.jetbrains.annotations.NotNull;
33 import org.jetbrains.annotations.Nullable;
34
35 public class JavaChangeSignatureHandler implements ChangeSignatureHandler {
36
37   public void invoke(@NotNull Project project, Editor editor, PsiFile file, DataContext dataContext) {
38     editor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE);
39     PsiElement element = findTargetMember(file, editor);
40     if (element == null) {
41       element = LangDataKeys.PSI_ELEMENT.getData(dataContext);
42     }
43     invokeOnElement(project, editor, element);
44   }
45
46   private static void invokeOnElement(Project project, Editor editor, PsiElement element) {
47     if (element instanceof PsiMethod) {
48       invoke((PsiMethod) element, project, editor);
49     }
50     else if (element instanceof PsiClass) {
51       invoke((PsiClass) element, editor);
52     }
53     else {
54       String message = RefactoringBundle.getCannotRefactorMessage(RefactoringBundle.message("error.wrong.caret.position.method.or.class.name"));
55       CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, HelpID.CHANGE_SIGNATURE);
56     }
57   }
58
59   public void invoke(@NotNull final Project project, @NotNull final PsiElement[] elements, final DataContext dataContext) {
60     if (elements.length != 1) return;
61     Editor editor = PlatformDataKeys.EDITOR.getData(dataContext);
62     invokeOnElement(project, editor, elements[0]);
63   }
64
65   private static void invoke(final PsiMethod method, final Project project, @Nullable final Editor editor) {
66     if (!CommonRefactoringUtil.checkReadOnlyStatus(project, method)) return;
67
68     PsiMethod newMethod = SuperMethodWarningUtil.checkSuperMethod(method, RefactoringBundle.message("to.refactor"));
69     if (newMethod == null) return;
70
71     if (!newMethod.equals(method)) {
72       invoke(newMethod, project, editor);
73       return;
74     }
75
76     if (!CommonRefactoringUtil.checkReadOnlyStatus(project, method)) return;
77
78     final PsiClass containingClass = method.getContainingClass();
79     final PsiReferenceExpression refExpr = editor != null ? TargetElementUtil.findReferenceExpression(editor) : null;
80     final ChangeSignatureDialog dialog = new ChangeSignatureDialog(project, method, containingClass != null && !containingClass.isInterface(),
81                                                                    refExpr);
82     dialog.show();
83   }
84
85   private static void invoke(final PsiClass aClass, Editor editor) {
86     final PsiTypeParameterList typeParameterList = aClass.getTypeParameterList();
87     Project project = aClass.getProject();
88     if (typeParameterList == null) {
89       final String message = RefactoringBundle.getCannotRefactorMessage(RefactoringBundle.message("changeClassSignature.no.type.parameters"));
90       CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, HelpID.CHANGE_CLASS_SIGNATURE);
91       return;
92     }
93     if (!CommonRefactoringUtil.checkReadOnlyStatus(project, aClass)) return;
94
95     ChangeClassSignatureDialog dialog = new ChangeClassSignatureDialog(aClass);
96     dialog.show();
97   }
98
99   @Nullable
100   public PsiMember findTargetMember(PsiFile file, Editor editor) {
101     PsiElement element = file.findElementAt(editor.getCaretModel().getOffset());
102     if (PsiTreeUtil.getParentOfType(element, PsiParameterList.class) != null) {
103       return PsiTreeUtil.getParentOfType(element, PsiMethod.class);
104     }
105
106     final PsiMethodCallExpression expression = PsiTreeUtil.getParentOfType(element, PsiMethodCallExpression.class);
107     if (expression != null) {
108       assert element != null;
109       final PsiExpression qualifierExpression = expression.getMethodExpression().getQualifierExpression();
110       if (PsiTreeUtil.isAncestor(qualifierExpression, element, false)) {
111         final PsiExpressionList expressionList = PsiTreeUtil.getParentOfType(qualifierExpression, PsiExpressionList.class);
112         if (expressionList != null) {
113           final PsiElement parent = expressionList.getParent();
114           if (parent instanceof PsiMethodCallExpression) {
115             return ((PsiMethodCallExpression)parent).resolveMethod();
116           }
117         }
118       }
119       else {
120         return expression.resolveMethod();
121       }
122     }
123
124     final PsiTypeParameterList typeParameterList = PsiTreeUtil.getParentOfType(element, PsiTypeParameterList.class);
125     if (typeParameterList != null) {
126       return PsiTreeUtil.getParentOfType(typeParameterList, PsiMember.class);
127     }
128
129     final PsiReferenceParameterList referenceParameterList = PsiTreeUtil.getParentOfType(element, PsiReferenceParameterList.class);
130     if (referenceParameterList != null) {
131       final PsiJavaCodeReferenceElement referenceElement =
132         PsiTreeUtil.getParentOfType(referenceParameterList, PsiJavaCodeReferenceElement.class);
133       if (referenceElement != null) {
134         final PsiElement resolved = referenceElement.resolve();
135         if (resolved instanceof PsiClass) {
136           return (PsiMember)resolved;
137         }
138         else if (resolved instanceof PsiMethod) {
139           return (PsiMember)resolved;
140         }
141       }
142     }
143     return null;
144   }
145 }