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