ability to change name of method to any string constant. Detection of incorrect usages
[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 PsiElement findTargetMember(PsiFile file, Editor editor) {
101     PsiElement element = file.findElementAt(editor.getCaretModel().getOffset());
102     return findTargetMember(element);
103   }
104
105   public PsiElement findTargetMember(PsiElement element) {
106     if (PsiTreeUtil.getParentOfType(element, PsiParameterList.class) != null) {
107       return PsiTreeUtil.getParentOfType(element, PsiMethod.class);
108     }
109
110     if (element.getParent() instanceof PsiMethod && ((PsiMethod)element.getParent()).getNameIdentifier()==element) {
111       return element.getParent();
112     }
113
114     final PsiMethodCallExpression expression = PsiTreeUtil.getParentOfType(element, PsiMethodCallExpression.class);
115     if (expression != null) {
116       assert element != null;
117       final PsiExpression qualifierExpression = expression.getMethodExpression().getQualifierExpression();
118       if (PsiTreeUtil.isAncestor(qualifierExpression, element, false)) {
119         final PsiExpressionList expressionList = PsiTreeUtil.getParentOfType(qualifierExpression, PsiExpressionList.class);
120         if (expressionList != null) {
121           final PsiElement parent = expressionList.getParent();
122           if (parent instanceof PsiMethodCallExpression) {
123             return ((PsiMethodCallExpression)parent).resolveMethod();
124           }
125         }
126       }
127       else {
128         return expression.resolveMethod();
129       }
130     }
131
132     final PsiTypeParameterList typeParameterList = PsiTreeUtil.getParentOfType(element, PsiTypeParameterList.class);
133     if (typeParameterList != null) {
134       return PsiTreeUtil.getParentOfType(typeParameterList, PsiMember.class);
135     }
136
137     final PsiReferenceParameterList referenceParameterList = PsiTreeUtil.getParentOfType(element, PsiReferenceParameterList.class);
138     if (referenceParameterList != null) {
139       final PsiJavaCodeReferenceElement referenceElement =
140         PsiTreeUtil.getParentOfType(referenceParameterList, PsiJavaCodeReferenceElement.class);
141       if (referenceElement != null) {
142         final PsiElement resolved = referenceElement.resolve();
143         if (resolved instanceof PsiClass) {
144           return resolved;
145         }
146         else if (resolved instanceof PsiMethod) {
147           return resolved;
148         }
149       }
150     }
151     return null;
152   }
153 }