2 * Copyright 2000-2014 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.codeInsight.AnnotationUtil;
19 import com.intellij.codeInsight.ExceptionUtil;
20 import com.intellij.codeInsight.daemon.impl.analysis.JavaHighlightUtil;
21 import com.intellij.codeInsight.daemon.impl.quickfix.RemoveUnusedVariableUtil;
22 import com.intellij.codeInspection.dataFlow.ControlFlowAnalyzer;
23 import com.intellij.lang.StdLanguages;
24 import com.intellij.lang.java.JavaLanguage;
25 import com.intellij.openapi.application.ApplicationManager;
26 import com.intellij.openapi.diagnostic.Logger;
27 import com.intellij.openapi.project.Project;
28 import com.intellij.openapi.util.Ref;
29 import com.intellij.openapi.util.text.StringUtil;
30 import com.intellij.psi.*;
31 import com.intellij.psi.codeStyle.CodeStyleManager;
32 import com.intellij.psi.codeStyle.JavaCodeStyleManager;
33 import com.intellij.psi.codeStyle.VariableKind;
34 import com.intellij.psi.scope.processor.VariablesProcessor;
35 import com.intellij.psi.scope.util.PsiScopesUtil;
36 import com.intellij.psi.search.LocalSearchScope;
37 import com.intellij.psi.search.searches.ReferencesSearch;
38 import com.intellij.psi.util.*;
39 import com.intellij.refactoring.RefactoringBundle;
40 import com.intellij.refactoring.rename.RenameUtil;
41 import com.intellij.refactoring.rename.ResolveSnapshotProvider;
42 import com.intellij.refactoring.util.*;
43 import com.intellij.refactoring.util.usageInfo.DefaultConstructorImplicitUsageInfo;
44 import com.intellij.refactoring.util.usageInfo.NoConstructorClassUsageInfo;
45 import com.intellij.usageView.UsageInfo;
46 import com.intellij.util.ArrayUtil;
47 import com.intellij.util.IncorrectOperationException;
48 import com.intellij.util.VisibilityUtil;
49 import com.intellij.util.containers.ContainerUtil;
50 import com.intellij.util.containers.HashSet;
51 import com.intellij.util.containers.MultiMap;
52 import org.jetbrains.annotations.NotNull;
53 import org.jetbrains.annotations.Nullable;
58 * @author Maxim.Medvedev
60 public class JavaChangeSignatureUsageProcessor implements ChangeSignatureUsageProcessor {
61 private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.changeSignature.JavaChangeSignatureUsageProcessor");
63 private static boolean isJavaUsage(UsageInfo info) {
64 final PsiElement element = info.getElement();
65 if (element == null) return false;
66 return element.getLanguage() == StdLanguages.JAVA;
70 public UsageInfo[] findUsages(ChangeInfo info) {
71 if (info instanceof JavaChangeInfo) {
72 return new JavaChangeSignatureUsageSearcher((JavaChangeInfo)info).findUsages();
75 return UsageInfo.EMPTY_ARRAY;
80 public MultiMap<PsiElement, String> findConflicts(ChangeInfo info, Ref<UsageInfo[]> refUsages) {
81 if (info instanceof JavaChangeInfo) {
82 return new ConflictSearcher((JavaChangeInfo)info).findConflicts(refUsages);
85 return new MultiMap<>();
90 public boolean processUsage(ChangeInfo changeInfo, UsageInfo usage, boolean beforeMethodChange, UsageInfo[] usages) {
91 if (!isJavaUsage(usage)) return false;
92 if (!(changeInfo instanceof JavaChangeInfo)) return false;
95 if (beforeMethodChange) {
96 if (usage instanceof CallerUsageInfo) {
97 final CallerUsageInfo callerUsageInfo = (CallerUsageInfo)usage;
98 processCallerMethod((JavaChangeInfo)changeInfo, callerUsageInfo.getMethod(), null, callerUsageInfo.isToInsertParameter(),
99 callerUsageInfo.isToInsertException());
102 else if (usage instanceof OverriderUsageInfo) {
103 OverriderUsageInfo info = (OverriderUsageInfo)usage;
104 final PsiMethod method = info.getOverridingMethod();
105 final PsiMethod baseMethod = info.getBaseMethod();
106 if (info.isOriginalOverrider()) {
107 processPrimaryMethod((JavaChangeInfo)changeInfo, method, baseMethod, false);
110 processCallerMethod((JavaChangeInfo)changeInfo, method, baseMethod, info.isToInsertArgs(), info.isToCatchExceptions());
114 else if (usage instanceof MethodReferenceUsageInfo && MethodReferenceUsageInfo.needToExpand((JavaChangeInfo)changeInfo)) {
115 final PsiElement element = usage.getElement();
116 if (element instanceof PsiMethodReferenceExpression ) {
117 final PsiExpression expression = LambdaRefactoringUtil.convertToMethodCallInLambdaBody((PsiMethodReferenceExpression)element);
118 if (expression instanceof PsiCallExpression) {
119 ((MethodReferenceUsageInfo)usage).setCallExpression((PsiCallExpression)expression);
124 else if (usage instanceof FunctionalInterfaceChangedUsageInfo) {
125 final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(usage.getProject());
126 final PsiElement element = usage.getElement();
127 final PsiMethod interfaceMethod = ((FunctionalInterfaceChangedUsageInfo)usage).getMethod();
128 if (element instanceof PsiLambdaExpression) {
129 processMethodParams((JavaChangeInfo)changeInfo, interfaceMethod,
130 elementFactory, PsiSubstitutor.EMPTY, ((PsiLambdaExpression)element).getParameterList(), ((PsiLambdaExpression)element).getBody());
132 else if (element instanceof PsiMethodReferenceExpression) {
133 final PsiLambdaExpression lambdaExpression =
134 LambdaRefactoringUtil.convertMethodReferenceToLambda((PsiMethodReferenceExpression)element, false, true);
135 if (lambdaExpression != null) {
136 processMethodParams(((JavaChangeInfo)changeInfo), interfaceMethod, elementFactory, PsiSubstitutor.EMPTY,
137 lambdaExpression.getParameterList(), lambdaExpression.getBody());
145 PsiElement element = usage.getElement();
146 LOG.assertTrue(element != null);
148 if (usage instanceof DefaultConstructorImplicitUsageInfo) {
149 final DefaultConstructorImplicitUsageInfo defConstructorUsage = (DefaultConstructorImplicitUsageInfo)usage;
150 PsiMethod constructor = defConstructorUsage.getConstructor();
151 if (!constructor.isPhysical()) {
152 final boolean toPropagate =
153 changeInfo instanceof JavaChangeInfoImpl && ((JavaChangeInfoImpl)changeInfo).propagateParametersMethods.remove(constructor);
154 final PsiClass containingClass = defConstructorUsage.getContainingClass();
155 constructor = (PsiMethod)containingClass.add(constructor);
156 PsiUtil.setModifierProperty(constructor, VisibilityUtil.getVisibilityModifier(containingClass.getModifierList()), true);
158 ((JavaChangeInfoImpl)changeInfo).propagateParametersMethods.add(constructor);
161 addSuperCall((JavaChangeInfo)changeInfo, constructor, defConstructorUsage.getBaseConstructor(), usages);
164 else if (usage instanceof NoConstructorClassUsageInfo) {
165 addDefaultConstructor(((JavaChangeInfo)changeInfo), ((NoConstructorClassUsageInfo)usage).getPsiClass(), usages);
168 else if (usage instanceof MethodReferenceUsageInfo && MethodReferenceUsageInfo.needToExpand((JavaChangeInfo)changeInfo)) {
169 final MethodCallUsageInfo methodCallInfo = ((MethodReferenceUsageInfo)usage).createMethodCallInfo();
170 if (methodCallInfo != null) {
171 processMethodUsage(methodCallInfo.getElement(), (JavaChangeInfo)changeInfo, methodCallInfo.isToChangeArguments(),
172 methodCallInfo.isToCatchExceptions(), methodCallInfo.getReferencedMethod(), methodCallInfo.getSubstitutor(), usages);
176 else if (usage instanceof MethodCallUsageInfo) {
177 final MethodCallUsageInfo methodCallInfo = (MethodCallUsageInfo)usage;
178 processMethodUsage(methodCallInfo.getElement(), (JavaChangeInfo)changeInfo, methodCallInfo.isToChangeArguments(),
179 methodCallInfo.isToCatchExceptions(), methodCallInfo.getReferencedMethod(), methodCallInfo.getSubstitutor(), usages);
182 else if (usage instanceof ChangeSignatureParameterUsageInfo) {
183 String newName = ((ChangeSignatureParameterUsageInfo)usage).newParameterName;
184 String oldName = ((ChangeSignatureParameterUsageInfo)usage).oldParameterName;
185 processParameterUsage((PsiReferenceExpression)element, oldName, newName);
188 else if (usage instanceof CallReferenceUsageInfo) {
189 ((CallReferenceUsageInfo)usage).getReference().handleChangeSignature(changeInfo);
192 else if (element instanceof PsiEnumConstant) {
193 fixActualArgumentsList(((PsiEnumConstant)element).getArgumentList(), (JavaChangeInfo)changeInfo, true, PsiSubstitutor.EMPTY);
196 else if (!(usage instanceof OverriderUsageInfo)) {
197 PsiReference reference = usage instanceof MoveRenameUsageInfo ? usage.getReference() : element.getReference();
198 if (reference != null) {
199 PsiElement target = changeInfo.getMethod();
200 if (target != null) {
201 reference.bindToElement(target);
209 private static void processParameterUsage(PsiReferenceExpression ref, String oldName, String newName)
210 throws IncorrectOperationException {
212 PsiElement last = ref.getReferenceNameElement();
213 if (last instanceof PsiIdentifier && last.getText().equals(oldName)) {
214 PsiElementFactory factory = JavaPsiFacade.getInstance(ref.getProject()).getElementFactory();
215 PsiIdentifier newNameIdentifier = factory.createIdentifier(newName);
216 last.replace(newNameIdentifier);
221 private static void addDefaultConstructor(JavaChangeInfo changeInfo, PsiClass aClass, final UsageInfo[] usages)
222 throws IncorrectOperationException {
223 if (!(aClass instanceof PsiAnonymousClass)) {
224 PsiElementFactory factory = JavaPsiFacade.getElementFactory(aClass.getProject());
225 PsiMethod defaultConstructor = factory.createMethodFromText(aClass.getName() + "(){}", aClass);
226 defaultConstructor = (PsiMethod)CodeStyleManager.getInstance(aClass.getProject()).reformat(defaultConstructor);
227 defaultConstructor = (PsiMethod)aClass.add(defaultConstructor);
228 PsiUtil.setModifierProperty(defaultConstructor, VisibilityUtil.getVisibilityModifier(aClass.getModifierList()), true);
229 addSuperCall(changeInfo, defaultConstructor, null, usages);
232 final PsiElement parent = aClass.getParent();
233 if (parent instanceof PsiNewExpression) {
234 final PsiExpressionList argumentList = ((PsiNewExpression)parent).getArgumentList();
235 final PsiClass baseClass = changeInfo.getMethod().getContainingClass();
236 final PsiSubstitutor substitutor = TypeConversionUtil.getSuperClassSubstitutor(baseClass, aClass, PsiSubstitutor.EMPTY);
237 fixActualArgumentsList(argumentList, changeInfo, true, substitutor);
242 private static void addSuperCall(JavaChangeInfo changeInfo, PsiMethod constructor, PsiMethod callee, final UsageInfo[] usages)
243 throws IncorrectOperationException {
244 final PsiElementFactory factory = JavaPsiFacade.getElementFactory(constructor.getProject());
245 PsiExpressionStatement superCall = (PsiExpressionStatement)factory.createStatementFromText("super();", constructor);
246 PsiCodeBlock body = constructor.getBody();
248 PsiStatement[] statements = body.getStatements();
249 if (statements.length > 0) {
250 superCall = (PsiExpressionStatement)body.addBefore(superCall, statements[0]);
253 superCall = (PsiExpressionStatement)body.add(superCall);
255 PsiMethodCallExpression callExpression = (PsiMethodCallExpression)superCall.getExpression();
256 final PsiClass aClass = constructor.getContainingClass();
257 final PsiClass baseClass = changeInfo.getMethod().getContainingClass();
258 final PsiSubstitutor substitutor = TypeConversionUtil.getSuperClassSubstitutor(baseClass, aClass, PsiSubstitutor.EMPTY);
259 processMethodUsage(callExpression.getMethodExpression(), changeInfo, true, false, callee, substitutor, usages);
262 private static void processMethodUsage(PsiElement ref,
263 JavaChangeInfo changeInfo,
264 boolean toChangeArguments,
265 boolean toCatchExceptions,
266 PsiMethod callee, PsiSubstitutor subsitutor, final UsageInfo[] usages) throws IncorrectOperationException {
267 if (changeInfo.isNameChanged()) {
268 if (ref instanceof PsiJavaCodeReferenceElement) {
269 PsiElement last = ((PsiJavaCodeReferenceElement)ref).getReferenceNameElement();
270 if (last instanceof PsiIdentifier && last.getText().equals(changeInfo.getOldName())) {
271 last.replace(changeInfo.getNewNameIdentifier());
276 final PsiMethod caller = RefactoringUtil.getEnclosingMethod(ref);
277 if (toChangeArguments) {
278 final PsiExpressionList list = RefactoringUtil.getArgumentListByMethodReference(ref);
279 LOG.assertTrue(list != null);
280 boolean toInsertDefaultValue = needDefaultValue(changeInfo, caller);
281 if (toInsertDefaultValue && ref instanceof PsiReferenceExpression) {
282 final PsiExpression qualifierExpression = ((PsiReferenceExpression)ref).getQualifierExpression();
283 if (qualifierExpression instanceof PsiSuperExpression && callerSignatureIsAboutToChangeToo(caller, usages)) {
284 toInsertDefaultValue = false;
288 fixActualArgumentsList(list, changeInfo, toInsertDefaultValue, subsitutor);
291 if (toCatchExceptions) {
292 if (!(ref instanceof PsiReferenceExpression &&
293 JavaHighlightUtil.isSuperOrThisCall(PsiTreeUtil.getParentOfType(ref, PsiStatement.class), true, false))) {
294 if (needToCatchExceptions(changeInfo, caller)) {
295 PsiClassType[] newExceptions =
296 callee != null ? getCalleeChangedExceptionInfo(callee) : getPrimaryChangedExceptionInfo(changeInfo);
297 fixExceptions(ref, newExceptions);
303 private static boolean callerSignatureIsAboutToChangeToo(final PsiMethod caller, final UsageInfo[] usages) {
304 for (UsageInfo usage : usages) {
305 if (usage instanceof MethodCallUsageInfo &&
306 MethodSignatureUtil.isSuperMethod(((MethodCallUsageInfo)usage).getReferencedMethod(), caller)) {
313 private static PsiClassType[] getCalleeChangedExceptionInfo(final PsiMethod callee) {
314 return callee.getThrowsList().getReferencedTypes(); //Callee method's throws list is already modified!
317 private static void fixExceptions(PsiElement ref, PsiClassType[] newExceptions) throws IncorrectOperationException {
318 //methods' throws lists are already modified, may use ExceptionUtil.collectUnhandledExceptions
319 newExceptions = filterCheckedExceptions(newExceptions);
321 PsiElement context = PsiTreeUtil.getParentOfType(ref, PsiTryStatement.class, PsiMethod.class, PsiLambdaExpression.class);
322 if (context instanceof PsiTryStatement) {
323 PsiTryStatement tryStatement = (PsiTryStatement)context;
324 PsiCodeBlock tryBlock = tryStatement.getTryBlock();
326 //Remove unused catches
327 Collection<PsiClassType> classes = ExceptionUtil.collectUnhandledExceptions(tryBlock, tryBlock);
328 PsiParameter[] catchParameters = tryStatement.getCatchBlockParameters();
329 for (PsiParameter parameter : catchParameters) {
330 final PsiType caughtType = parameter.getType();
332 if (!(caughtType instanceof PsiClassType)) continue;
333 if (ExceptionUtil.isUncheckedExceptionOrSuperclass((PsiClassType)caughtType)) continue;
335 if (!isCatchParameterRedundant((PsiClassType)caughtType, classes)) continue;
336 parameter.getParent().delete(); //delete catch section
339 PsiClassType[] exceptionsToAdd = filterUnhandledExceptions(newExceptions, tryBlock);
340 addExceptions(exceptionsToAdd, tryStatement);
342 adjustPossibleEmptyTryStatement(tryStatement);
345 newExceptions = filterUnhandledExceptions(newExceptions, ref);
346 if (newExceptions.length > 0) {
347 //Add new try statement
348 PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(ref.getProject());
349 PsiTryStatement tryStatement = (PsiTryStatement)elementFactory.createStatementFromText("try {} catch (Exception e) {}", null);
351 PsiElement lambdaBody = context instanceof PsiLambdaExpression ? ((PsiLambdaExpression)context).getBody() : null;
352 if (lambdaBody instanceof PsiExpression) {
353 PsiCodeBlock codeBlock = (PsiCodeBlock)((PsiLambdaExpression)RefactoringUtil.expandExpressionLambdaToCodeBlock(lambdaBody)).getBody();
354 LOG.assertTrue(codeBlock != null);
355 anchor = codeBlock.getStatements()[0];
358 anchor = PsiTreeUtil.getParentOfType(ref, PsiStatement.class);
360 LOG.assertTrue(anchor != null);
361 tryStatement.getTryBlock().add(anchor);
362 tryStatement = (PsiTryStatement)anchor.getParent().addAfter(tryStatement, anchor);
364 addExceptions(newExceptions, tryStatement);
366 tryStatement.getCatchSections()[0].delete(); //Delete dummy catch section
371 public static boolean hasNewCheckedExceptions(JavaChangeInfo changeInfo) {
372 return filterCheckedExceptions(getPrimaryChangedExceptionInfo(changeInfo)).length > 0;
375 private static PsiClassType[] filterCheckedExceptions(PsiClassType[] exceptions) {
376 List<PsiClassType> result = new ArrayList<>();
377 for (PsiClassType exceptionType : exceptions) {
378 if (!ExceptionUtil.isUncheckedException(exceptionType)) result.add(exceptionType);
380 return result.toArray(new PsiClassType[result.size()]);
383 private static void adjustPossibleEmptyTryStatement(PsiTryStatement tryStatement) throws IncorrectOperationException {
384 PsiCodeBlock tryBlock = tryStatement.getTryBlock();
385 if (tryBlock != null) {
386 if (tryStatement.getCatchSections().length == 0 &&
387 tryStatement.getFinallyBlock() == null) {
388 PsiElement firstBodyElement = tryBlock.getFirstBodyElement();
389 if (firstBodyElement != null) {
390 tryStatement.getParent().addRangeAfter(firstBodyElement, tryBlock.getLastBodyElement(), tryStatement);
392 tryStatement.delete();
397 private static void addExceptions(PsiClassType[] exceptionsToAdd, PsiTryStatement tryStatement) throws IncorrectOperationException {
398 for (PsiClassType type : exceptionsToAdd) {
399 final JavaCodeStyleManager styleManager = JavaCodeStyleManager.getInstance(tryStatement.getProject());
400 String name = styleManager.suggestVariableName(VariableKind.PARAMETER, null, null, type).names[0];
401 name = styleManager.suggestUniqueVariableName(name, tryStatement, false);
403 PsiCatchSection catchSection =
404 JavaPsiFacade.getInstance(tryStatement.getProject()).getElementFactory().createCatchSection(type, name, tryStatement);
405 tryStatement.add(catchSection);
409 private static PsiClassType[] filterUnhandledExceptions(PsiClassType[] exceptions, PsiElement place) {
410 List<PsiClassType> result = new ArrayList<>();
411 for (PsiClassType exception : exceptions) {
412 if (!ExceptionUtil.isHandled(exception, place)) result.add(exception);
414 return result.toArray(new PsiClassType[result.size()]);
417 private static boolean isCatchParameterRedundant(PsiClassType catchParamType, Collection<PsiClassType> thrownTypes) {
418 for (PsiType exceptionType : thrownTypes) {
419 if (exceptionType.isConvertibleFrom(catchParamType)) return false;
424 //This methods works equally well for primary usages as well as for propagated callers' usages
425 private static void fixActualArgumentsList(PsiExpressionList list,
426 JavaChangeInfo changeInfo,
427 boolean toInsertDefaultValue,
428 PsiSubstitutor substitutor) throws IncorrectOperationException {
429 final PsiElementFactory factory = JavaPsiFacade.getInstance(list.getProject()).getElementFactory();
430 if (changeInfo.isParameterSetOrOrderChanged()) {
431 if (changeInfo instanceof JavaChangeInfoImpl && ((JavaChangeInfoImpl)changeInfo).isPropagationEnabled) {
432 final ParameterInfoImpl[] createdParmsInfo = ((JavaChangeInfoImpl)changeInfo).getCreatedParmsInfoWithoutVarargs();
433 for (ParameterInfoImpl info : createdParmsInfo) {
434 PsiExpression newArg;
435 if (toInsertDefaultValue) {
436 newArg = createDefaultValue(changeInfo, factory, info, list, substitutor);
439 newArg = factory.createExpressionFromText(info.getName(), list);
441 if (newArg != null) JavaCodeStyleManager.getInstance(list.getProject()).shortenClassReferences(list.add(newArg));
445 final PsiExpression[] args = list.getExpressions();
446 final int nonVarargCount = getNonVarargCount(changeInfo, args);
447 final int varargCount = args.length - nonVarargCount;
448 if (varargCount<0) return;
449 PsiExpression[] newVarargInitializers = null;
451 final int newArgsLength;
452 final int newNonVarargCount;
453 final JavaParameterInfo[] newParms = changeInfo.getNewParameters();
454 if (changeInfo.isArrayToVarargs()) {
455 newNonVarargCount = newParms.length - 1;
456 final JavaParameterInfo lastNewParm = newParms[newParms.length - 1];
457 final PsiExpression arrayToConvert = args[lastNewParm.getOldIndex()];
458 if (arrayToConvert instanceof PsiNewExpression) {
459 final PsiNewExpression expression = (PsiNewExpression)arrayToConvert;
460 final PsiArrayInitializerExpression arrayInitializer = expression.getArrayInitializer();
461 if (arrayInitializer != null) {
462 newVarargInitializers = arrayInitializer.getInitializers();
465 newArgsLength = newVarargInitializers == null ? newParms.length : newNonVarargCount + newVarargInitializers.length;
467 else if (changeInfo.isRetainsVarargs()) {
468 newNonVarargCount = newParms.length - 1;
469 newArgsLength = newNonVarargCount + varargCount;
471 else if (changeInfo.isObtainsVarags()) {
472 newNonVarargCount = newParms.length - 1;
473 newArgsLength = newNonVarargCount;
476 newNonVarargCount = newParms.length;
477 newArgsLength = newParms.length;
480 String[] oldVarargs = null;
481 if (changeInfo.wasVararg() && !changeInfo.isRetainsVarargs()) {
482 oldVarargs = new String[varargCount];
483 for (int i = nonVarargCount; i < args.length; i++) {
484 oldVarargs[i - nonVarargCount] = args[i].getText();
488 final PsiExpression[] newArgs = new PsiExpression[newArgsLength];
489 for (int i = 0; i < newNonVarargCount; i++) {
490 if (newParms[i].getOldIndex() == nonVarargCount && oldVarargs != null) {
491 PsiType type = newParms[i].createType(changeInfo.getMethod(), list.getManager());
492 if (type instanceof PsiArrayType) {
493 type = substitutor.substitute(type);
494 type = TypeConversionUtil.erasure(type);
495 String typeText = type.getCanonicalText();
496 if (type instanceof PsiEllipsisType) {
497 typeText = typeText.replace("...", "[]");
499 String text = "new " + typeText + "{" + StringUtil.join(oldVarargs, ",") + "}";
500 newArgs[i] = factory.createExpressionFromText(text, changeInfo.getMethod());
504 newArgs[i] = createActualArgument(changeInfo, list, newParms[i], toInsertDefaultValue, args, substitutor);
506 if (changeInfo.isArrayToVarargs()) {
507 if (newVarargInitializers == null) {
508 newArgs[newNonVarargCount] =
509 createActualArgument(changeInfo, list, newParms[newNonVarargCount], toInsertDefaultValue, args, substitutor);
512 System.arraycopy(newVarargInitializers, 0, newArgs, newNonVarargCount, newVarargInitializers.length);
516 final int newVarargCount = newArgsLength - newNonVarargCount;
517 LOG.assertTrue(newVarargCount == 0 || newVarargCount == varargCount);
518 for (int i = newNonVarargCount; i < newArgsLength; i++){
519 final int oldIndex = newParms[newNonVarargCount].getOldIndex();
520 if (oldIndex >= 0 && oldIndex != nonVarargCount) {
521 newArgs[i] = createActualArgument(changeInfo, list, newParms[newNonVarargCount], toInsertDefaultValue, args, substitutor);
523 System.arraycopy(args, nonVarargCount, newArgs, newNonVarargCount, newVarargCount);
528 ChangeSignatureUtil.synchronizeList(list, Arrays.asList(newArgs), ExpressionList.INSTANCE, changeInfo.toRemoveParm());
533 private static int getNonVarargCount(JavaChangeInfo changeInfo, PsiExpression[] args) {
534 if (!changeInfo.wasVararg()) return args.length;
535 return changeInfo.getOldParameterTypes().length - 1;
540 private static PsiExpression createActualArgument(JavaChangeInfo changeInfo,
541 final PsiExpressionList list,
542 final JavaParameterInfo info,
543 final boolean toInsertDefaultValue,
544 final PsiExpression[] args,
545 PsiSubstitutor substitutor) throws IncorrectOperationException {
546 final PsiElementFactory factory = JavaPsiFacade.getInstance(list.getProject()).getElementFactory();
547 final int index = info.getOldIndex();
548 if (index >= 0 && index < args.length) {
552 if (toInsertDefaultValue) {
553 return createDefaultValue(changeInfo, factory, info, list, substitutor);
556 return factory.createExpressionFromText(info.getName(), list);
562 private static PsiExpression createDefaultValue(JavaChangeInfo changeInfo,
563 final PsiElementFactory factory,
564 final JavaParameterInfo info,
565 final PsiExpressionList list, PsiSubstitutor substitutor)
566 throws IncorrectOperationException {
567 if (info.isUseAnySingleVariable()) {
568 final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(list.getProject()).getResolveHelper();
569 final PsiType type = info.getTypeWrapper().getType(changeInfo.getMethod(), list.getManager());
570 final VariablesProcessor processor = new VariablesProcessor(false) {
572 protected boolean check(PsiVariable var, ResolveState state) {
573 if (var instanceof PsiField && !resolveHelper.isAccessible((PsiField)var, list, null)) return false;
574 if (var instanceof PsiLocalVariable && list.getTextRange().getStartOffset() <= var.getTextRange().getStartOffset()) return false;
575 if (PsiTreeUtil.isAncestor(var, list, false)) return false;
576 final PsiType varType = state.get(PsiSubstitutor.KEY).substitute(var.getType());
577 return type.isAssignableFrom(varType);
581 public boolean execute(@NotNull PsiElement pe, @NotNull ResolveState state) {
582 super.execute(pe, state);
586 PsiScopesUtil.treeWalkUp(processor, list, null);
587 if (processor.size() == 1) {
588 final PsiVariable result = processor.getResult(0);
589 return factory.createExpressionFromText(result.getName(), list);
591 if (processor.size() == 0) {
592 final PsiClass parentClass = PsiTreeUtil.getParentOfType(list, PsiClass.class);
593 if (parentClass != null) {
594 PsiClass containingClass = parentClass;
595 final Set<PsiClass> containingClasses = new HashSet<>();
596 while (containingClass != null) {
597 if (type.isAssignableFrom(factory.createType(containingClass, PsiSubstitutor.EMPTY))) {
598 containingClasses.add(containingClass);
600 containingClass = PsiTreeUtil.getParentOfType(containingClass, PsiClass.class);
602 if (containingClasses.size() == 1) {
603 return RefactoringChangeUtil.createThisExpression(parentClass.getManager(), containingClasses.contains(parentClass) ? null
610 final PsiCallExpression callExpression = PsiTreeUtil.getParentOfType(list, PsiCallExpression.class);
611 final String defaultValue = info.getDefaultValue();
612 return callExpression != null ? (PsiExpression)info.getActualValue(callExpression, substitutor)
613 : !StringUtil.isEmpty(defaultValue) ? factory.createExpressionFromText(defaultValue, list) : null;
618 public boolean processPrimaryMethod(ChangeInfo changeInfo) {
619 if (!StdLanguages.JAVA.equals(changeInfo.getLanguage()) || !(changeInfo instanceof JavaChangeInfo)) return false;
620 final PsiElement element = changeInfo.getMethod();
621 LOG.assertTrue(element instanceof PsiMethod);
622 if (!JavaLanguage.INSTANCE.equals(element.getLanguage())) return false;
623 if (changeInfo.isGenerateDelegate()) {
624 generateDelegate((JavaChangeInfo)changeInfo);
626 processPrimaryMethod((JavaChangeInfo)changeInfo, (PsiMethod)element, null, true);
631 public boolean shouldPreviewUsages(ChangeInfo changeInfo, UsageInfo[] usages) {
636 public boolean setupDefaultValues(ChangeInfo changeInfo, Ref<UsageInfo[]> refUsages, Project project) {
637 if (!(changeInfo instanceof JavaChangeInfo)) return true;
638 for (UsageInfo usageInfo : refUsages.get()) {
639 if (usageInfo instanceof MethodCallUsageInfo) {
640 MethodCallUsageInfo methodCallUsageInfo = (MethodCallUsageInfo)usageInfo;
641 if (methodCallUsageInfo.isToChangeArguments()){
642 final PsiElement element = methodCallUsageInfo.getElement();
643 if (element == null) continue;
644 final PsiMethod caller = RefactoringUtil.getEnclosingMethod(element);
645 final boolean needDefaultValue = needDefaultValue(changeInfo, caller);
646 if (needDefaultValue && (caller == null || !MethodSignatureUtil.isSuperMethod(methodCallUsageInfo.getReferencedMethod(), caller))) {
647 final ParameterInfo[] parameters = changeInfo.getNewParameters();
648 for (ParameterInfo parameter : parameters) {
649 final String defaultValue = parameter.getDefaultValue();
650 if (defaultValue == null && parameter.getOldIndex() == -1) {
651 ((ParameterInfoImpl)parameter).setDefaultValue("");
652 if (!ApplicationManager.getApplication().isUnitTestMode()) {
653 final PsiType type = ((ParameterInfoImpl)parameter).getTypeWrapper().getType(element);
654 final DefaultValueChooser chooser =
655 new DefaultValueChooser(project, parameter.getName(), PsiTypesUtil.getDefaultValueOfType(type));
656 if (chooser.showAndGet()) {
657 if (chooser.feelLucky()) {
658 parameter.setUseAnySingleVariable(true);
661 ((ParameterInfoImpl)parameter).setDefaultValue(chooser.getDefaultValue());
678 public void registerConflictResolvers(List<ResolveSnapshotProvider.ResolveSnapshot> snapshots,
679 @NotNull ResolveSnapshotProvider resolveSnapshotProvider,
680 UsageInfo[] usages, ChangeInfo changeInfo) {
681 snapshots.add(resolveSnapshotProvider.createSnapshot(changeInfo.getMethod()));
682 for (UsageInfo usage : usages) {
683 if (usage instanceof OverriderUsageInfo) {
684 snapshots.add(resolveSnapshotProvider.createSnapshot(((OverriderUsageInfo)usage).getOverridingMethod()));
689 private static boolean needDefaultValue(ChangeInfo changeInfo, @Nullable PsiMethod method) {
690 if (!(changeInfo instanceof JavaChangeInfoImpl)) {
693 if (method != null) {
694 final Set<PsiMethod> parametersMethods = ((JavaChangeInfoImpl)changeInfo).propagateParametersMethods;
695 if (parametersMethods.contains(method)) {
698 for (PsiMethod superMethod : method.findDeepestSuperMethods()) {
699 if (parametersMethods.contains(superMethod)) {
707 public static void generateDelegate(JavaChangeInfo changeInfo) throws IncorrectOperationException {
708 final PsiMethod delegate = (PsiMethod)changeInfo.getMethod().copy();
709 final PsiClass targetClass = changeInfo.getMethod().getContainingClass();
710 LOG.assertTrue(targetClass != null);
711 if (targetClass.isInterface() && delegate.getBody() == null) {
712 delegate.getModifierList().setModifierProperty(PsiModifier.DEFAULT, true);
714 PsiElementFactory factory = JavaPsiFacade.getElementFactory(targetClass.getProject());
715 ChangeSignatureProcessor.makeEmptyBody(factory, delegate);
716 final PsiCallExpression callExpression = ChangeSignatureProcessor.addDelegatingCallTemplate(delegate, changeInfo.getNewName());
717 addDelegateArguments(changeInfo, factory, callExpression);
718 targetClass.addBefore(delegate, changeInfo.getMethod());
722 private static void addDelegateArguments(JavaChangeInfo changeInfo, PsiElementFactory factory, final PsiCallExpression callExpression) throws IncorrectOperationException {
723 final JavaParameterInfo[] newParms = changeInfo.getNewParameters();
724 final String[] oldParameterNames = changeInfo.getOldParameterNames();
725 for (JavaParameterInfo newParm : newParms) {
726 final PsiExpression actualArg;
727 if (newParm.getOldIndex() >= 0) {
728 actualArg = factory.createExpressionFromText(oldParameterNames[newParm.getOldIndex()], callExpression);
731 actualArg = (PsiExpression)newParm.getActualValue(callExpression, PsiSubstitutor.EMPTY);
733 final PsiExpressionList argumentList = callExpression.getArgumentList();
734 if (actualArg != null && argumentList != null) {
735 JavaCodeStyleManager.getInstance(callExpression.getProject()).shortenClassReferences(argumentList.add(actualArg));
740 private static void processPrimaryMethod(JavaChangeInfo changeInfo, PsiMethod method,
741 PsiMethod baseMethod,
742 boolean isOriginal) throws IncorrectOperationException {
743 PsiElementFactory factory = JavaPsiFacade.getInstance(method.getProject()).getElementFactory();
745 if (changeInfo.isVisibilityChanged()) {
746 PsiModifierList modifierList = method.getModifierList();
747 final String highestVisibility = isOriginal
748 ? changeInfo.getNewVisibility()
749 : VisibilityUtil.getHighestVisibility(changeInfo.getNewVisibility(),
750 VisibilityUtil.getVisibilityModifier(modifierList));
751 VisibilityUtil.setVisibility(modifierList, highestVisibility);
754 if (changeInfo.isNameChanged()) {
755 String newName = baseMethod == null ? changeInfo.getNewName() :
756 RefactoringUtil.suggestNewOverriderName(method.getName(), baseMethod.getName(), changeInfo.getNewName());
758 if (newName != null && !newName.equals(method.getName())) {
759 final PsiIdentifier nameId = method.getNameIdentifier();
760 assert nameId != null;
761 nameId.replace(JavaPsiFacade.getInstance(method.getProject()).getElementFactory().createIdentifier(newName));
765 final PsiSubstitutor substitutor =
766 baseMethod == null ? PsiSubstitutor.EMPTY : ChangeSignatureProcessor.calculateSubstitutor(method, baseMethod);
768 final JavaCodeStyleManager javaCodeStyleManager = JavaCodeStyleManager.getInstance(method.getProject());
769 if (changeInfo.isReturnTypeChanged()) {
770 PsiType newTypeElement = changeInfo.getNewReturnType().getType(changeInfo.getMethod().getParameterList(), method.getManager());
771 final PsiType returnType = substitutor.substitute(newTypeElement);
772 // don't modify return type for non-Java overriders (EJB)
773 if (method.getName().equals(changeInfo.getNewName())) {
774 final PsiTypeElement typeElement = method.getReturnTypeElement();
775 if (typeElement != null) {
776 javaCodeStyleManager.shortenClassReferences(typeElement.replace(factory.createTypeElement(returnType)));
781 PsiParameterList list = method.getParameterList();
782 int newParamsLength = processMethodParams(changeInfo, baseMethod, factory, substitutor, list, method.getBody());
783 fixJavadocsForChangedMethod(method, changeInfo, newParamsLength);
784 if (changeInfo.isExceptionSetOrOrderChanged()) {
785 final PsiClassType[] newExceptions = getPrimaryChangedExceptionInfo(changeInfo);
786 fixPrimaryThrowsLists(method, newExceptions);
789 if (baseMethod == null && method.findSuperMethods().length == 0) {
790 final PsiAnnotation annotation = AnnotationUtil.findAnnotation(method, true, Override.class.getName());
791 if (annotation != null) {
797 private static int processMethodParams(JavaChangeInfo changeInfo,
798 PsiMethod baseMethod,
799 PsiElementFactory factory,
800 PsiSubstitutor substitutor,
801 PsiParameterList list,
802 PsiElement methodBody) {
803 PsiParameter[] parameters = list.getParameters();
805 final JavaParameterInfo[] parameterInfos = changeInfo.getNewParameters();
806 final int delta = baseMethod != null ? baseMethod.getParameterList().getParametersCount() - list.getParametersCount() : 0;
807 PsiParameter[] newParms = new PsiParameter[Math.max(parameterInfos.length - delta, 0)];
808 final String[] oldParameterNames = changeInfo.getOldParameterNames();
809 final String[] oldParameterTypes = changeInfo.getOldParameterTypes();
810 for (int i = 0; i < newParms.length; i++) {
811 JavaParameterInfo info = parameterInfos[i];
812 int index = info.getOldIndex();
814 PsiParameter parameter = parameters[index];
815 newParms[i] = parameter;
817 String oldName = oldParameterNames[index];
818 if (!oldName.equals(info.getName()) && oldName.equals(parameter.getName())) {
819 PsiIdentifier newIdentifier = factory.createIdentifier(info.getName());
820 parameter.getNameIdentifier().replace(newIdentifier);
823 final PsiTypeElement typeElement = parameter.getTypeElement();
824 if (typeElement != null) {
825 String oldType = oldParameterTypes[index];
826 if (!oldType.equals(info.getTypeText())) {
827 parameter.normalizeDeclaration();
829 substitutor.substitute(info.createType(changeInfo.getMethod().getParameterList(), changeInfo.getMethod().getManager()));
830 typeElement.replace(factory.createTypeElement(newType));
835 newParms[i] = createNewParameter(changeInfo, info, substitutor);
840 resolveParameterVsFieldsConflicts(newParms, list, changeInfo.toRemoveParm(), methodBody);
841 return newParms.length;
844 private static PsiClassType[] getPrimaryChangedExceptionInfo(JavaChangeInfo changeInfo) throws IncorrectOperationException {
845 final ThrownExceptionInfo[] newExceptionInfos = changeInfo.getNewExceptions();
846 PsiClassType[] newExceptions = new PsiClassType[newExceptionInfos.length];
847 final PsiMethod method = changeInfo.getMethod();
848 for (int i = 0; i < newExceptions.length; i++) {
850 (PsiClassType)newExceptionInfos[i].createType(method, method.getManager()); //context really does not matter here
852 return newExceptions;
856 private static void processCallerMethod(JavaChangeInfo changeInfo, PsiMethod caller,
857 PsiMethod baseMethod,
858 boolean toInsertParams,
859 boolean toInsertThrows) throws IncorrectOperationException {
860 LOG.assertTrue(toInsertParams || toInsertThrows);
861 if (toInsertParams) {
862 List<PsiParameter> newParameters = new ArrayList<>();
863 ContainerUtil.addAll(newParameters, caller.getParameterList().getParameters());
864 final JavaParameterInfo[] primaryNewParms = changeInfo.getNewParameters();
865 PsiSubstitutor substitutor =
866 baseMethod == null ? PsiSubstitutor.EMPTY : ChangeSignatureProcessor.calculateSubstitutor(caller, baseMethod);
867 final PsiClass aClass = changeInfo.getMethod().getContainingClass();
868 final PsiClass callerContainingClass = caller.getContainingClass();
869 final PsiSubstitutor psiSubstitutor = aClass != null && callerContainingClass != null && callerContainingClass.isInheritor(aClass, true)
870 ? TypeConversionUtil.getSuperClassSubstitutor(aClass, callerContainingClass, substitutor)
871 : PsiSubstitutor.EMPTY;
872 for (JavaParameterInfo info : primaryNewParms) {
873 if (info.getOldIndex() < 0) newParameters.add(createNewParameter(changeInfo, info, psiSubstitutor, substitutor));
875 PsiParameter[] arrayed = newParameters.toArray(new PsiParameter[newParameters.size()]);
876 boolean[] toRemoveParm = new boolean[arrayed.length];
877 Arrays.fill(toRemoveParm, false);
878 resolveParameterVsFieldsConflicts(arrayed, caller.getParameterList(), toRemoveParm, caller.getBody());
881 if (toInsertThrows) {
882 List<PsiJavaCodeReferenceElement> newThrowns = new ArrayList<>();
883 final PsiReferenceList throwsList = caller.getThrowsList();
884 ContainerUtil.addAll(newThrowns, throwsList.getReferenceElements());
885 final ThrownExceptionInfo[] primaryNewExns = changeInfo.getNewExceptions();
886 for (ThrownExceptionInfo thrownExceptionInfo : primaryNewExns) {
887 if (thrownExceptionInfo.getOldIndex() < 0) {
888 final PsiClassType type = (PsiClassType)thrownExceptionInfo.createType(caller, caller.getManager());
889 final PsiJavaCodeReferenceElement ref =
890 JavaPsiFacade.getInstance(caller.getProject()).getElementFactory().createReferenceElementByType(type);
894 PsiJavaCodeReferenceElement[] arrayed = newThrowns.toArray(new PsiJavaCodeReferenceElement[newThrowns.size()]);
895 boolean[] toRemoveParm = new boolean[arrayed.length];
896 Arrays.fill(toRemoveParm, false);
897 ChangeSignatureUtil.synchronizeList(throwsList, Arrays.asList(arrayed), ThrowsList.INSTANCE, toRemoveParm);
901 private static void fixPrimaryThrowsLists(PsiMethod method, PsiClassType[] newExceptions) throws IncorrectOperationException {
902 PsiElementFactory elementFactory = JavaPsiFacade.getInstance(method.getProject()).getElementFactory();
903 PsiJavaCodeReferenceElement[] refs = new PsiJavaCodeReferenceElement[newExceptions.length];
904 for (int i = 0; i < refs.length; i++) {
905 refs[i] = elementFactory.createReferenceElementByType(newExceptions[i]);
907 PsiReferenceList throwsList = elementFactory.createReferenceList(refs);
909 PsiReferenceList methodThrowsList = (PsiReferenceList)method.getThrowsList().replace(throwsList);
910 methodThrowsList = (PsiReferenceList)JavaCodeStyleManager.getInstance(method.getProject()).shortenClassReferences(methodThrowsList);
911 CodeStyleManager.getInstance(method.getManager().getProject())
912 .reformatRange(method, method.getParameterList().getTextRange().getEndOffset(),
913 methodThrowsList.getTextRange().getEndOffset());
916 private static void fixJavadocsForChangedMethod(final PsiMethod method, final JavaChangeInfo changeInfo, int newParamsLength) throws IncorrectOperationException {
917 final PsiParameter[] parameters = method.getParameterList().getParameters();
918 final JavaParameterInfo[] newParms = changeInfo.getNewParameters();
919 LOG.assertTrue(parameters.length <= newParamsLength);
920 final Set<PsiParameter> newParameters = new HashSet<>();
921 final String[] oldParameterNames = changeInfo.getOldParameterNames();
922 for (int i = 0; i < newParamsLength; i++) {
923 JavaParameterInfo newParm = newParms[i];
924 if (newParm.getOldIndex() < 0 ||
925 newParm.getOldIndex() == i && !(newParm.getName().equals(oldParameterNames[newParm.getOldIndex()]) && newParm.getTypeText().equals(changeInfo.getOldParameterTypes()[newParm.getOldIndex()]))) {
926 newParameters.add(parameters[i]);
929 RefactoringUtil.fixJavadocsForParams(method, newParameters, pair -> {
930 final PsiParameter parameter = pair.first;
931 final String oldParamName = pair.second;
932 final int idx = ArrayUtil.find(oldParameterNames, oldParamName);
933 return idx >= 0 && idx == method.getParameterList().getParameterIndex(parameter) && changeInfo.getNewParameters()[idx].getOldIndex() == idx;
934 }, paramName -> ArrayUtil.find(oldParameterNames, paramName) >= 0);
937 private static PsiParameter createNewParameter(JavaChangeInfo changeInfo, JavaParameterInfo newParm,
938 PsiSubstitutor... substitutor) throws IncorrectOperationException {
939 final PsiParameterList list = changeInfo.getMethod().getParameterList();
940 final PsiElementFactory factory = JavaPsiFacade.getInstance(list.getProject()).getElementFactory();
941 PsiType type = newParm.createType(list);
942 for (PsiSubstitutor psiSubstitutor : substitutor) {
943 type = psiSubstitutor.substitute(type);
945 return factory.createParameter(newParm.getName(), type);
948 private static void resolveParameterVsFieldsConflicts(final PsiParameter[] newParms,
949 final PsiParameterList list,
950 boolean[] toRemoveParm,
951 final PsiElement methodBody) throws IncorrectOperationException {
952 List<FieldConflictsResolver> conflictResolvers = new ArrayList<>();
953 for (PsiParameter parameter : newParms) {
954 conflictResolvers.add(new FieldConflictsResolver(parameter.getName(), methodBody));
956 ChangeSignatureUtil.synchronizeList(list, Arrays.asList(newParms), ParameterList.INSTANCE, toRemoveParm);
957 JavaCodeStyleManager.getInstance(list.getProject()).shortenClassReferences(list);
958 for (FieldConflictsResolver fieldConflictsResolver : conflictResolvers) {
959 fieldConflictsResolver.fix();
963 private static boolean needToCatchExceptions(JavaChangeInfo changeInfo, PsiMethod caller) {
964 return changeInfo.isExceptionSetOrOrderChanged() &&
965 !(changeInfo instanceof JavaChangeInfoImpl && ((JavaChangeInfoImpl)changeInfo).propagateExceptionsMethods.contains(caller));
968 private static class ParameterList implements ChangeSignatureUtil.ChildrenGenerator<PsiParameterList, PsiParameter> {
969 public static final ParameterList INSTANCE = new ParameterList();
972 public List<PsiParameter> getChildren(PsiParameterList psiParameterList) {
973 return Arrays.asList(psiParameterList.getParameters());
977 private static class ThrowsList implements ChangeSignatureUtil.ChildrenGenerator<PsiReferenceList, PsiJavaCodeReferenceElement> {
978 public static final ThrowsList INSTANCE = new ThrowsList();
981 public List<PsiJavaCodeReferenceElement> getChildren(PsiReferenceList throwsList) {
982 return Arrays.asList(throwsList.getReferenceElements());
986 private static class ConflictSearcher {
987 private final JavaChangeInfo myChangeInfo;
989 private ConflictSearcher(@NotNull JavaChangeInfo changeInfo) {
990 this.myChangeInfo = changeInfo;
993 public MultiMap<PsiElement, String> findConflicts(Ref<UsageInfo[]> refUsages) {
994 MultiMap<PsiElement, String> conflictDescriptions = new MultiMap<>();
995 final PsiMethod prototype = addMethodConflicts(conflictDescriptions);
996 Set<UsageInfo> usagesSet = new HashSet<>(Arrays.asList(refUsages.get()));
997 RenameUtil.removeConflictUsages(usagesSet);
998 if (myChangeInfo.isVisibilityChanged()) {
1000 addInaccessibilityDescriptions(usagesSet, conflictDescriptions);
1002 catch (IncorrectOperationException e) {
1007 final boolean[] toRemove = myChangeInfo.toRemoveParm();
1008 //introduce parameter object deletes parameters but replaces their usages with generated code
1009 final boolean checkUnusedParameter = myChangeInfo.checkUnusedParameter();
1010 if (checkUnusedParameter) {
1011 checkParametersToDelete(myChangeInfo.getMethod(), toRemove, conflictDescriptions);
1013 checkContract(conflictDescriptions, myChangeInfo.getMethod());
1015 for (UsageInfo usageInfo : usagesSet) {
1016 final PsiElement element = usageInfo.getElement();
1017 if (usageInfo instanceof OverriderUsageInfo) {
1018 final PsiMethod method = ((OverriderUsageInfo)usageInfo).getOverridingMethod();
1019 final PsiMethod baseMethod = ((OverriderUsageInfo)usageInfo).getBaseMethod();
1020 final int delta = baseMethod.getParameterList().getParametersCount() - method.getParameterList().getParametersCount();
1022 if (toRemove[toRemove.length - 1]) { //todo check if implicit parameter is not the last one
1023 conflictDescriptions.putValue(baseMethod, "Implicit last parameter should not be deleted");
1026 else if (prototype != null && baseMethod == myChangeInfo.getMethod()) {
1027 ConflictsUtil.checkMethodConflicts(method.getContainingClass(), method, prototype, conflictDescriptions);
1028 if (checkUnusedParameter) {
1029 checkParametersToDelete(method, toRemove, conflictDescriptions);
1033 checkContract(conflictDescriptions, method);
1035 else if (element instanceof PsiMethodReferenceExpression && MethodReferenceUsageInfo.needToExpand(myChangeInfo)) {
1036 conflictDescriptions.putValue(element, RefactoringBundle.message("expand.method.reference.warning"));
1038 else if (element instanceof PsiJavaCodeReferenceElement) {
1039 final PsiElement parent = element.getParent();
1040 if (parent instanceof PsiCallExpression) {
1041 final PsiExpressionList argumentList = ((PsiCallExpression)parent).getArgumentList();
1042 if (argumentList != null) {
1043 final PsiExpression[] args = argumentList.getExpressions();
1044 for (int i = 0; i < toRemove.length; i++) {
1045 if (toRemove[i] && i < args.length) {
1046 if (RemoveUnusedVariableUtil.checkSideEffects(args[i], null, new ArrayList<>())) {
1047 conflictDescriptions.putValue(args[i], "Parameter '" + myChangeInfo.getOldParameterNames()[i] + "' has usage that is not safe to delete");
1056 return conflictDescriptions;
1059 private static void checkParametersToDelete(PsiMethod method, boolean[] toRemove, MultiMap<PsiElement, String> conflictDescriptions) {
1060 final PsiParameter[] parameters = method.getParameterList().getParameters();
1061 final PsiCodeBlock body = method.getBody();
1063 final LocalSearchScope searchScope = new LocalSearchScope(body);
1064 for (int i = 0; i < toRemove.length; i++) {
1065 if (toRemove[i] && ReferencesSearch.search(parameters[i], searchScope).findFirst() != null) {
1066 conflictDescriptions.putValue(parameters[i], StringUtil.capitalize(RefactoringUIUtil.getDescription(parameters[i], true)) + " is used in method body");
1072 private static void checkContract(MultiMap<PsiElement, String> conflictDescriptions, PsiMethod method) {
1073 PsiAnnotation contract = ControlFlowAnalyzer.findContractAnnotation(method);
1074 if (contract != null && !AnnotationUtil.isInferredAnnotation(contract)) {
1075 conflictDescriptions.putValue(method, "@Contract annotation will have to be changed manually");
1079 private boolean needToChangeCalls() {
1080 return myChangeInfo.isNameChanged() || myChangeInfo.isParameterSetOrOrderChanged() || myChangeInfo.isExceptionSetOrOrderChanged();
1084 private void addInaccessibilityDescriptions(Set<UsageInfo> usages, MultiMap<PsiElement, String> conflictDescriptions)
1085 throws IncorrectOperationException {
1086 PsiMethod method = myChangeInfo.getMethod();
1087 PsiModifierList modifierList = (PsiModifierList)method.getModifierList().copy();
1088 VisibilityUtil.setVisibility(modifierList, myChangeInfo.getNewVisibility());
1090 for (Iterator<UsageInfo> iterator = usages.iterator(); iterator.hasNext();) {
1091 UsageInfo usageInfo = iterator.next();
1092 PsiElement element = usageInfo.getElement();
1093 if (element != null) {
1094 if (element instanceof PsiQualifiedReference) {
1095 PsiClass accessObjectClass = null;
1096 PsiElement qualifier = ((PsiQualifiedReference)element).getQualifier();
1097 if (qualifier instanceof PsiExpression) {
1098 accessObjectClass = (PsiClass)PsiUtil.getAccessObjectClass((PsiExpression)qualifier).getElement();
1101 if (!JavaPsiFacade.getInstance(element.getProject()).getResolveHelper()
1102 .isAccessible(method, modifierList, element, accessObjectClass, null)) {
1104 RefactoringBundle.message("0.with.1.visibility.is.not.accessible.from.2",
1105 RefactoringUIUtil.getDescription(method, true),
1106 VisibilityUtil.toPresentableText(myChangeInfo.getNewVisibility()),
1107 RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(element), true));
1108 conflictDescriptions.putValue(method, message);
1109 if (!needToChangeCalls()) {
1119 private PsiMethod addMethodConflicts(MultiMap<PsiElement, String> conflicts) {
1120 String newMethodName = myChangeInfo.getNewName();
1122 final PsiMethod method = myChangeInfo.getMethod();
1123 if (!StdLanguages.JAVA.equals(method.getLanguage())) return null;
1124 PsiManager manager = method.getManager();
1125 PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory();
1126 final CanonicalTypes.Type returnType = myChangeInfo.getNewReturnType();
1127 PsiMethod prototype;
1128 if (returnType != null) {
1129 prototype = factory.createMethod(newMethodName, returnType.getType(method, manager));
1132 prototype = factory.createConstructor();
1133 prototype.setName(newMethodName);
1135 JavaParameterInfo[] parameters = myChangeInfo.getNewParameters();
1138 for (JavaParameterInfo info : parameters) {
1139 PsiType parameterType = info.createType(method, manager);
1140 if (parameterType == null) {
1142 JavaPsiFacade.getElementFactory(method.getProject()).createTypeFromText(CommonClassNames.JAVA_LANG_OBJECT, method);
1144 PsiParameter param = factory.createParameter(info.getName(), parameterType);
1145 prototype.getParameterList().add(param);
1148 ConflictsUtil.checkMethodConflicts(method.getContainingClass(), myChangeInfo.isGenerateDelegate() ? null : method, prototype, conflicts);
1151 catch (IncorrectOperationException e) {
1158 private static class ExpressionList implements ChangeSignatureUtil.ChildrenGenerator<PsiExpressionList, PsiExpression> {
1159 public static final ExpressionList INSTANCE = new ExpressionList();
1162 public List<PsiExpression> getChildren(PsiExpressionList psiExpressionList) {
1163 return Arrays.asList(psiExpressionList.getExpressions());