inplace change signature: delegate in template
[idea/community.git] / java / java-impl / src / com / intellij / refactoring / changeSignature / JavaChangeSignatureDetector.java
1 /*
2  * Copyright 2000-2016 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.ide.highlighter.JavaFileType;
19 import com.intellij.openapi.diagnostic.Logger;
20 import com.intellij.openapi.editor.Editor;
21 import com.intellij.openapi.fileTypes.FileType;
22 import com.intellij.openapi.project.Project;
23 import com.intellij.openapi.util.TextRange;
24 import com.intellij.openapi.util.text.StringUtil;
25 import com.intellij.psi.*;
26 import com.intellij.psi.util.PsiTreeUtil;
27 import com.intellij.refactoring.changeSignature.inplace.LanguageChangeSignatureDetector;
28 import com.intellij.refactoring.util.CanonicalTypes;
29 import com.intellij.util.ObjectUtils;
30 import com.intellij.util.VisibilityUtil;
31 import org.jetbrains.annotations.NotNull;
32
33 import java.util.List;
34
35 /**
36  * User: anna
37  * Date: Sep 6, 2010
38  */
39 public class JavaChangeSignatureDetector implements LanguageChangeSignatureDetector<DetectedJavaChangeInfo> {
40   private static final Logger LOG = Logger.getInstance("#" + JavaChangeSignatureDetector.class.getName());
41
42   @NotNull
43   @Override
44   public DetectedJavaChangeInfo createInitialChangeInfo(final @NotNull PsiElement element) {
45     return DetectedJavaChangeInfo.createFromMethod(PsiTreeUtil.getParentOfType(element, PsiMethod.class), false);
46   }
47
48   @Override
49   public void performChange(final DetectedJavaChangeInfo changeInfo, Editor editor, @NotNull final String oldText) {
50     changeInfo.perform(oldText, editor, true);
51   }
52
53   @Override
54   public boolean isChangeSignatureAvailableOnElement(@NotNull PsiElement element, DetectedJavaChangeInfo currentInfo) {
55     final PsiMethod method = currentInfo.getMethod();
56     TextRange range = method.getTextRange();
57     PsiCodeBlock body = method.getBody();
58     if (body != null) {
59       range = new TextRange(range.getStartOffset(), body.getTextOffset());
60     }
61     return element.getContainingFile() == method.getContainingFile() && range.contains(element.getTextRange());
62   }
63
64   @Override
65   public boolean ignoreChanges(PsiElement element) {
66     if (element instanceof PsiMethod) return true;
67     return PsiTreeUtil.getParentOfType(element, PsiImportList.class) != null;
68   }
69
70   @Override
71   public TextRange getHighlightingRange(@NotNull DetectedJavaChangeInfo changeInfo) {
72     PsiElement method = changeInfo.getMethod();
73     return method != null ? getSignatureRange((PsiMethod)method) : null;
74   }
75
76   @Override
77   public String getMethodSignaturePreview(DetectedJavaChangeInfo initialChangeInfo,
78                                           final List<TextRange> deleteRanges,
79                                           final List<TextRange> newRanges) {
80     StringBuilder buf = new StringBuilder();
81     String visibility = VisibilityUtil.getVisibilityString(initialChangeInfo.getNewVisibility());
82     buf.append(visibility);
83     if (!StringUtil.isEmptyOrSpaces(visibility)) {
84       buf.append(" ");
85     }
86     CanonicalTypes.Type returnType = initialChangeInfo.getNewReturnType();
87     if (returnType != null) {
88       buf.append(returnType.getTypeText()).append(" ");
89     }
90     buf.append(initialChangeInfo.getNewName()).append("(");
91
92     JavaParameterInfo[] newParameters = initialChangeInfo.getNewParameters();
93     boolean first = true;
94     boolean[] toRemove = initialChangeInfo.toRemoveParm();
95     for (int i = 0; i < toRemove.length; i++) {
96       if (first) {
97         first = false;
98       }
99       else {
100         buf.append(", ");
101       }
102
103       if (toRemove[i]) {
104         String deletedParam = initialChangeInfo.getOldParameterTypes()[i] + " " + initialChangeInfo.getOldParameterNames()[i];
105         deleteRanges.add(new TextRange(buf.length(), buf.length() + deletedParam.length()));
106         buf.append(deletedParam);
107       }
108       else {
109         for (JavaParameterInfo parameter : newParameters) {
110           if (parameter.getOldIndex() == i) {
111             buf.append(parameter.getTypeText()).append(" ").append(parameter.getName());
112             break;
113           }
114         }
115       }
116     }
117
118     for (JavaParameterInfo param : newParameters) {
119       if (param.getOldIndex() == -1) {
120         if (first) {
121           first = false;
122         }
123         else {
124           buf.append(", ");
125         }
126         String paramPresentation = param.getTypeText() + " " + ObjectUtils.notNull(param.getName(), "");
127         newRanges.add(new TextRange(buf.length(), buf.length() + paramPresentation.length()));
128         buf.append(paramPresentation);
129       }
130     }
131     buf.append(")");
132     return buf.toString();
133   }
134
135   @Override
136   public FileType getFileType() {
137     return JavaFileType.INSTANCE;
138   }
139
140   @Override
141   public DetectedJavaChangeInfo createNextChangeInfo(String signature, @NotNull final DetectedJavaChangeInfo currentInfo, boolean delegate) {
142     final PsiElement currentInfoMethod = currentInfo.getMethod();
143     if (currentInfoMethod == null) {
144       return null;
145     }
146     final Project project = currentInfoMethod.getProject();
147
148     final PsiMethod oldMethod = currentInfo.getMethod();
149     String visibility = "";
150     PsiClass containingClass = oldMethod.getContainingClass();
151     if (containingClass != null && containingClass.isInterface()) {
152       visibility = PsiModifier.PUBLIC + " ";
153     }
154     PsiMethod method = JavaPsiFacade.getElementFactory(project).createMethodFromText((visibility + signature).trim(), oldMethod);
155     return currentInfo.createNextInfo(method, delegate);
156   }
157
158   public static TextRange getSignatureRange(PsiMethod method) {
159     int endOffset = method.getThrowsList().getTextRange().getEndOffset();
160     int startOffset = method.getTextRange().getStartOffset();
161     return new TextRange(startOffset, endOffset);
162   }
163 }