2 * Copyright 2000-2016 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package com.intellij.refactoring.changeSignature;
18 import com.intellij.lang.findUsages.DescriptiveNameUtil;
19 import com.intellij.openapi.application.ApplicationManager;
20 import com.intellij.openapi.command.CommandProcessor;
21 import com.intellij.openapi.editor.Document;
22 import com.intellij.openapi.project.Project;
23 import com.intellij.openapi.util.Comparing;
24 import com.intellij.openapi.util.TextRange;
25 import com.intellij.psi.*;
26 import com.intellij.refactoring.BaseRefactoringProcessor;
27 import com.intellij.refactoring.RefactoringBundle;
28 import com.intellij.refactoring.changeSignature.inplace.InplaceChangeSignature;
29 import com.intellij.refactoring.util.CanonicalTypes;
30 import com.intellij.usageView.UsageInfo;
31 import com.intellij.util.IncorrectOperationException;
32 import com.intellij.util.VisibilityUtil;
33 import org.jetbrains.annotations.NotNull;
34 import org.jetbrains.annotations.Nullable;
36 import java.util.HashMap;
37 import java.util.HashSet;
44 class DetectedJavaChangeInfo extends JavaChangeInfoImpl {
45 private PsiMethod mySuperMethod;
46 private final String[] myModifiers;
48 DetectedJavaChangeInfo(@PsiModifier.ModifierConstant String newVisibility,
50 CanonicalTypes.Type newType,
51 @NotNull ParameterInfoImpl[] newParms,
52 ThrownExceptionInfo[] newExceptions,
53 String newName, String oldName, final boolean delegate) {
54 super(newVisibility, method, newName, newType, newParms, newExceptions, delegate, new HashSet<>(), new HashSet<>(), oldName);
55 final PsiParameter[] parameters = method.getParameterList().getParameters();
56 myModifiers = new String[parameters.length];
57 for (int i = 0; i < parameters.length; i++) {
58 PsiParameter parameter = parameters[i];
59 final PsiModifierList modifierList = parameter.getModifierList();
60 if (modifierList != null) {
61 final String text = modifierList.getText();
62 myModifiers[i] = text;
68 static DetectedJavaChangeInfo createFromMethod(PsiMethod method, final boolean delegate) {
69 final String newVisibility = VisibilityUtil.getVisibilityModifier(method.getModifierList());
70 final PsiType returnType = method.getReturnType();
71 final CanonicalTypes.Type newReturnType = returnType != null ? CanonicalTypes.createTypeWrapper(returnType) : null;
72 final ParameterInfoImpl[] parameterInfos = ParameterInfoImpl.fromMethod(method);
73 for (ParameterInfoImpl parameterInfo : parameterInfos) {
74 if (!parameterInfo.getTypeWrapper().isValid()) {
78 final DetectedJavaChangeInfo fromMethod = new DetectedJavaChangeInfo(newVisibility, method, newReturnType, parameterInfos, null, method.getName(), method.getName(), delegate);
79 final PsiMethod deepestSuperMethod = method.findDeepestSuperMethod();
80 if (deepestSuperMethod != null) {
81 if (!deepestSuperMethod.getManager().isInProject(deepestSuperMethod)) return null;
83 fromMethod.setSuperMethod(deepestSuperMethod);
88 protected void setupPropagationEnabled(PsiParameter[] parameters, ParameterInfoImpl[] newParams) {
89 isPropagationEnabled = false;
92 public PsiMethod getSuperMethod() {
93 if (mySuperMethod == null) {
99 public void setSuperMethod(PsiMethod superMethod) {
100 mySuperMethod = superMethod;
103 public String[] getModifiers() {
108 protected boolean checkMethodEquality() {
113 DetectedJavaChangeInfo createNextInfo(final PsiMethod method, boolean delegate) {
114 final DetectedJavaChangeInfo fromMethod = createFromMethod(method, delegate);
115 if (fromMethod == null) return null;
116 if (!this.equals(fromMethod)) {
117 if (!createParametersInfo(fromMethod.newParms)) return null;
118 if ((fromMethod.newReturnType != null && getNewReturnType() == null) ||
119 (fromMethod.newReturnType == null && getNewReturnType() != null) ||
120 (fromMethod.newReturnType != null && getNewReturnType() != null && !Comparing.strEqual(getNewReturnType().getTypeText(),
121 fromMethod.newReturnType.getTypeText()))) {
122 final String visibility = getNewVisibility();
123 if (Comparing.strEqual(visibility, PsiModifier.PRIVATE) &&
124 !isArrayToVarargs() &&
125 !isExceptionSetOrOrderChanged() &&
126 !isExceptionSetChanged() &&
128 !isParameterSetOrOrderChanged() &&
129 !isParameterNamesChanged() &&
130 !isParameterTypesChanged()) {
136 final DetectedJavaChangeInfo javaChangeInfo =
137 new DetectedJavaChangeInfo(fromMethod.getNewVisibility(), getMethod(), fromMethod.newReturnType, fromMethod.newParms, getNewExceptions(), method.getName(), getOldName(), delegate) {
139 protected void fillOldParams(PsiMethod method) {
140 oldParameterNames = DetectedJavaChangeInfo.this.getOldParameterNames();
141 oldParameterTypes = DetectedJavaChangeInfo.this.getOldParameterTypes();
142 if (!method.isConstructor()) {
144 isReturnTypeChanged = isReturnTypeChanged ||
145 (DetectedJavaChangeInfo.this.getNewReturnType() != null
146 ? !Comparing.strEqual(DetectedJavaChangeInfo.this.getNewReturnType().getTypeText(), newReturnType.getTypeText())
147 : newReturnType != null);
149 catch (IncorrectOperationException e) {
150 isReturnTypeChanged = true;
154 for (int i = 0, length = Math.min(newParms.length, oldParameterNames.length); i < length; i++) {
155 ParameterInfoImpl parm = newParms[i];
156 if (parm.getName().equals(oldParameterNames[i]) && parm.getTypeText().equals(oldParameterTypes[i])) {
157 parm.oldParameterIndex = i;
162 javaChangeInfo.setSuperMethod(getSuperMethod());
163 return javaChangeInfo;
165 catch (IncorrectOperationException e) {
172 ChangeSignatureProcessor createChangeSignatureProcessor(final PsiMethod method) {
173 return new ChangeSignatureProcessor(method.getProject(), new DetectedJavaChangeInfo(getNewVisibility(), getSuperMethod(),
175 (ParameterInfoImpl[])getNewParameters(),
176 getNewExceptions(), getNewName(),
177 method.getName(), false) {
179 protected void fillOldParams(PsiMethod method) {
180 super.fillOldParams(method);
181 oldParameterNames = DetectedJavaChangeInfo.this.getOldParameterNames();
182 oldParameterTypes = DetectedJavaChangeInfo.this.getOldParameterTypes();
186 protected void performRefactoring(@NotNull UsageInfo[] usages) {
187 super.performRefactoring(usages);
188 final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(method.getProject());
189 final PsiParameter[] parameters = method.getParameterList().getParameters();
190 for (int i = 0; i < getModifiers().length; i++) {
191 final String modifier = getModifiers()[i];
192 final PsiModifierList modifierList = parameters[i].getModifierList();
193 if (modifierList != null && !Comparing.strEqual(modifier, modifierList.getText())) {
194 final PsiModifierList newModifierList =
195 elementFactory.createParameterFromText((modifier.isEmpty() ? "" : modifier + " ") + "type name", method).getModifierList();
196 if (newModifierList != null) {
197 modifierList.replace(newModifierList);
205 private boolean createParametersInfo(ParameterInfoImpl[] parameterInfos) {
206 final JavaParameterInfo[] oldParameters = getNewParameters();
207 final String[] oldParameterNames = getOldParameterNames();
208 final String[] oldParameterTypes = getOldParameterTypes();
209 final Map<JavaParameterInfo, Integer> untouchedParams = new HashMap<>();
210 for (int i = 0; i < parameterInfos.length; i++) {
211 ParameterInfoImpl parameterInfo = parameterInfos[i];
212 JavaParameterInfo oldParameter = null;
213 for (JavaParameterInfo parameter : oldParameters) {
214 if (Comparing.strEqual(parameter.getName(), parameterInfo.getName()) &&
215 Comparing.strEqual(parameter.getTypeText(), parameterInfo.getTypeText())) {
216 oldParameter = parameter;
221 if (oldParameter != null) {
222 parameterInfos[i] = new ParameterInfoImpl(oldParameter.getOldIndex(),
223 oldParameter.getName(),
224 oldParameter.getTypeWrapper(),
226 untouchedParams.put(parameterInfos[i], oldParameter.getOldIndex());
230 for (int i = 0; i < parameterInfos.length; i++) {
231 ParameterInfoImpl parameterInfo = parameterInfos[i];
232 if (!untouchedParams.containsKey(parameterInfo)) {
233 JavaParameterInfo oldParameter = null;
234 if (oldParameters.length > i && oldParameterNames.length > i) {
235 if (Comparing.strEqual(oldParameterNames[i], parameterInfo.getName()) ||
236 Comparing.strEqual(oldParameterTypes[i], parameterInfo.getTypeText())) {
237 if (!untouchedParams.containsValue(oldParameters[i].getOldIndex())) {
238 oldParameter = oldParameters[i];
242 final CanonicalTypes.Type typeWrapper = parameterInfo.getTypeWrapper();
243 if (!typeWrapper.isValid()) return false;
244 parameterInfos[i] = new ParameterInfoImpl(oldParameter != null ? oldParameter.getOldIndex() : -1,
245 parameterInfo.getName(),
253 boolean perform(ChangeInfo initialChangeInfo, final String oldText, boolean silently) {
254 final PsiMethod method = getSuperMethod();
256 Project project = initialChangeInfo.getMethod().getProject();
257 final PsiMethod currentMethod = (PsiMethod)initialChangeInfo.getMethod();
258 final TextRange signatureRange = JavaChangeSignatureDetector.getSignatureRange(currentMethod);
259 final PsiDocumentManager documentManager = PsiDocumentManager.getInstance(project);
260 final Document document = documentManager.getDocument(currentMethod.getContainingFile());
261 if (silently || ApplicationManager.getApplication().isUnitTestMode()) {
262 final String currentSignature = currentMethod.getContainingFile().getText().substring(signatureRange.getStartOffset(),
263 signatureRange.getEndOffset());
264 InplaceChangeSignature.temporallyRevertChanges(JavaChangeSignatureDetector.getSignatureRange(currentMethod), document, oldText, project);
265 createChangeSignatureProcessor(method).run();
266 InplaceChangeSignature
267 .temporallyRevertChanges(JavaChangeSignatureDetector.getSignatureRange(currentMethod), document, currentSignature, project);
270 final JavaMethodDescriptor descriptor = new JavaMethodDescriptor(currentMethod) {
272 public String getReturnTypeText() {
273 return getNewReturnType().getTypeText();
276 final JavaChangeSignatureDialog dialog =
277 new JavaChangeSignatureDialog(method.getProject(), descriptor, true, method) {
278 protected BaseRefactoringProcessor createRefactoringProcessor() {
279 return createChangeSignatureProcessor(method);
283 protected void invokeRefactoring(final BaseRefactoringProcessor processor) {
284 CommandProcessor.getInstance().executeCommand(myProject, () -> {
285 InplaceChangeSignature.temporallyRevertChanges(JavaChangeSignatureDetector.getSignatureRange(currentMethod), document, oldText, project);
286 doRefactor(processor);
287 }, RefactoringBundle.message("changing.signature.of.0", DescriptiveNameUtil.getDescriptiveName(currentMethod)), null);
290 private void doRefactor(BaseRefactoringProcessor processor) {
291 super.invokeRefactoring(processor);
294 return dialog.showAndGet();