From 99d845186c58ff59c8fb21dafed892d2401efa30 Mon Sep 17 00:00:00 2001 From: Eugene Vigdorchik Date: Wed, 16 Feb 2005 20:49:03 +0300 Subject: [PATCH] (no message) --- .../changeSignature/CallerUsageInfo.java | 32 ++ .../changeSignature/ChangeInfo.java | 81 +++- .../ChangeSignatureDialog.java | 28 +- .../ChangeSignatureProcessor.java | 450 +++++++++++------- .../changeSignature/MethodCallUsageInfo.java | 48 ++ .../changeSignature/OverriderUsageInfo.java | 43 ++ .../inCallers/CallerChooser.java | 47 +- .../changeSignature/inCallers/MethodNode.java | 9 +- .../memberPullUp/PullUpHelper.java | 4 +- ...eplaceConstructorWithFactoryProcessor.java | 2 +- .../refactoring/util/RefactoringUtil.java | 37 +- .../DefaultConstructorImplicitUsageInfo.java | 8 +- .../DefaultConstructorUsageCollector.java | 9 +- .../refactoring/ChangeSignatureTest.java | 3 - 14 files changed, 540 insertions(+), 261 deletions(-) create mode 100644 source/com/intellij/refactoring/changeSignature/CallerUsageInfo.java create mode 100644 source/com/intellij/refactoring/changeSignature/MethodCallUsageInfo.java create mode 100644 source/com/intellij/refactoring/changeSignature/OverriderUsageInfo.java diff --git a/source/com/intellij/refactoring/changeSignature/CallerUsageInfo.java b/source/com/intellij/refactoring/changeSignature/CallerUsageInfo.java new file mode 100644 index 000000000000..73665cecd977 --- /dev/null +++ b/source/com/intellij/refactoring/changeSignature/CallerUsageInfo.java @@ -0,0 +1,32 @@ +package com.intellij.refactoring.changeSignature; + +import com.intellij.psi.PsiMethod; +import com.intellij.usageView.UsageInfo; + +/** + * @author ven + */ +public class CallerUsageInfo extends UsageInfo { + private PsiMethod myMethod; + private final boolean myToInsertParameter; + private final boolean myToInsertException; + + public CallerUsageInfo(final PsiMethod method, boolean isToInsertParameter, boolean isToInsertException) { + super(method); + myMethod = method; + myToInsertParameter = isToInsertParameter; + myToInsertException = isToInsertException; + } + + public boolean isToInsertException() { + return myToInsertException; + } + + public boolean isToInsertParameter() { + return myToInsertParameter; + } + + public PsiMethod getMethod() { + return myMethod; + } +} diff --git a/source/com/intellij/refactoring/changeSignature/ChangeInfo.java b/source/com/intellij/refactoring/changeSignature/ChangeInfo.java index 885428b7a23a..dc64967c83ab 100644 --- a/source/com/intellij/refactoring/changeSignature/ChangeInfo.java +++ b/source/com/intellij/refactoring/changeSignature/ChangeInfo.java @@ -12,6 +12,8 @@ import com.intellij.refactoring.util.CanonicalTypes; import com.intellij.util.IncorrectOperationException; import java.util.Arrays; +import java.util.List; +import java.util.ArrayList; class ChangeInfo { private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.changeSignature.ChangeInfo"); @@ -25,7 +27,7 @@ class ChangeInfo { final String newName; final CanonicalTypes.Type newReturnType; final ParameterInfo[] newParms; - final ThrownExceptionInfo[] newExceptions; + ThrownExceptionInfo[] newExceptions; final boolean[] toRemoveParm; boolean isVisibilityChanged = false; boolean isNameChanged = false; @@ -35,6 +37,7 @@ class ChangeInfo { boolean isExceptionSetOrOrderChanged = false; boolean isParameterNamesChanged = false; boolean isParameterTypesChanged = false; + boolean isPropagationEnabled = true; final boolean wasVararg; final boolean retainsVarargs; final boolean obtainsVarags; @@ -89,7 +92,7 @@ class ChangeInfo { if (parameters.length != newParms.length){ this.isParameterSetOrOrderChanged = true; } - else{ + else { for(int i = 0; i < newParms.length; i++){ ParameterInfo parmInfo = newParms[i]; PsiParameter parameter = parameters[i]; @@ -111,28 +114,9 @@ class ChangeInfo { } } - if (newExceptions == null) newExceptions = extractExceptions(method); + setupPropagationEnabled(parameters, newParms); - this.newExceptions = newExceptions; - - PsiClassType[] types = method.getThrowsList().getReferencedTypes(); - isExceptionSetChanged = newExceptions.length != types.length; - if (!isExceptionSetChanged) { - for (int i = 0; i < newExceptions.length; i++) { - try { - if (newExceptions[i].oldIndex < 0 || !types[i].equals(newExceptions[i].myType.getType(method))) { - isExceptionSetChanged = true; - break; - } - } - catch (IncorrectOperationException e) { - isExceptionSetChanged = true; - } - if (newExceptions[i].oldIndex != i) isExceptionSetOrOrderChanged = true; - } - } - - isExceptionSetOrOrderChanged |= isExceptionSetChanged; + setupExceptions(newExceptions, method); this.toRemoveParm = new boolean[parameters.length]; Arrays.fill(this.toRemoveParm, true); @@ -169,6 +153,46 @@ class ChangeInfo { ejbRole = J2EERolesUtil.getEjbRole(method); } + private void setupExceptions(ThrownExceptionInfo[] newExceptions, final PsiMethod method) { + if (newExceptions == null) newExceptions = extractExceptions(method); + + this.newExceptions = newExceptions; + + PsiClassType[] types = method.getThrowsList().getReferencedTypes(); + isExceptionSetChanged = newExceptions.length != types.length; + if (!isExceptionSetChanged) { + for (int i = 0; i < newExceptions.length; i++) { + try { + if (newExceptions[i].oldIndex < 0 || !types[i].equals(newExceptions[i].myType.getType(method))) { + isExceptionSetChanged = true; + break; + } + } + catch (IncorrectOperationException e) { + isExceptionSetChanged = true; + } + if (newExceptions[i].oldIndex != i) isExceptionSetOrOrderChanged = true; + } + } + + isExceptionSetOrOrderChanged |= isExceptionSetChanged; + } + + private void setupPropagationEnabled(final PsiParameter[] parameters, final ParameterInfo[] newParms) { + if (parameters.length >= newParms.length) { + isPropagationEnabled = false; + } + else { + for (int i = 0; i < parameters.length; i++) { + final ParameterInfo newParm = newParms[i]; + if (newParm.oldParameterIndex != i) { + isPropagationEnabled = false; + break; + } + } + } + } + //create identity mapping private static ThrownExceptionInfo[] extractExceptions(PsiMethod method) { PsiClassType[] types = method.getThrowsList().getReferencedTypes(); @@ -186,4 +210,15 @@ class ChangeInfo { public void updateMethod(PsiMethod method) { this.method = method; } + + public ParameterInfo[] getCreatedParmsInfoWithoutVarargs() { + List result = new ArrayList(); + for (int i = 0; i < newParms.length; i++) { + ParameterInfo newParm = newParms[i]; + if (newParm.oldParameterIndex < 0 && !newParm.isVarargType()) { + result.add(newParm); + } + } + return result.toArray(new ParameterInfo[result.size()]); + } } diff --git a/source/com/intellij/refactoring/changeSignature/ChangeSignatureDialog.java b/source/com/intellij/refactoring/changeSignature/ChangeSignatureDialog.java index c103bbac749e..9f0f16ab9dd0 100644 --- a/source/com/intellij/refactoring/changeSignature/ChangeSignatureDialog.java +++ b/source/com/intellij/refactoring/changeSignature/ChangeSignatureDialog.java @@ -38,10 +38,8 @@ import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; -import java.util.ArrayList; -import java.util.LinkedHashSet; +import java.util.*; import java.util.List; -import java.util.StringTokenizer; public class ChangeSignatureDialog extends RefactoringDialog { private static final Logger LOG = Logger.getInstance( @@ -63,8 +61,8 @@ public class ChangeSignatureDialog extends RefactoringDialog { private ExceptionsTableModel myExceptionsTableModel; private JButton myPropagateParamChangesButton; private JButton myPropagateExnChangesButton; - private PsiMethod[] myMethodsToPropagateParameters = null; - private PsiMethod[] myMethodsToPropagateExceptions = null; + private Set myMethodsToPropagateParameters = null; + private Set myMethodsToPropagateExceptions = null; public ChangeSignatureDialog(Project project, PsiMethod method, boolean allowDelegation) { super(project, true); @@ -166,8 +164,8 @@ public class ChangeSignatureDialog extends RefactoringDialog { myPropagateParamChangesButton = new JButton("Propagate Parameters"); myPropagateParamChangesButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - new CallerChooser(myMethod, "Select Caller Methods To Apply Default Value") { - protected void callersChosen(PsiMethod[] callers) { + new CallerChooser(myMethod, "Select New Parameters Propagation End Points") { + protected void callersChosen(Set callers) { myMethodsToPropagateParameters = callers; } }.show(); @@ -178,8 +176,8 @@ public class ChangeSignatureDialog extends RefactoringDialog { myPropagateExnChangesButton = new JButton("Propagate Exceptions"); myPropagateExnChangesButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - new CallerChooser(myMethod, "Select Caller Methods To Insert Catch Statements") { - protected void callersChosen(PsiMethod[] callers) { + new CallerChooser(myMethod, "Select New Thrown Exceptions Propagation End Points") { + protected void callersChosen(Set callers) { myMethodsToPropagateExceptions = callers; } }.show(); @@ -334,14 +332,6 @@ public class ChangeSignatureDialog extends RefactoringDialog { myExceptionsTable.getColumnModel().getColumn(0).setCellEditor(new CodeFragmentTableCellEditor(myProject)); } - public PsiMethod[] getEndPointsToPropagateExceptions() { - return myMethodsToPropagateExceptions; - } - - public PsiMethod[] getEndPointsToPropagateParameters() { - return myMethodsToPropagateParameters; - } - private void completeVariable(EditorTextField editorTextField, PsiType type) { Editor editor = editorTextField.getEditor(); String prefix = editorTextField.getText(); @@ -518,8 +508,8 @@ public class ChangeSignatureDialog extends RefactoringDialog { invokeRefactoring(new ChangeSignatureProcessor(getProject(), myMethod, isGenerateDelegate(), getVisibility(), getMethodName(), getReturnType(), getParameters(), getExceptions(), - getEndPointsToPropagateParameters(), - getEndPointsToPropagateExceptions())); + myMethodsToPropagateParameters, + myMethodsToPropagateExceptions)); } private String validateAndCommitData() { diff --git a/source/com/intellij/refactoring/changeSignature/ChangeSignatureProcessor.java b/source/com/intellij/refactoring/changeSignature/ChangeSignatureProcessor.java index 485aa64e7a4d..5c9f7345eb38 100644 --- a/source/com/intellij/refactoring/changeSignature/ChangeSignatureProcessor.java +++ b/source/com/intellij/refactoring/changeSignature/ChangeSignatureProcessor.java @@ -17,9 +17,9 @@ import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; -import com.intellij.psi.javadoc.PsiDocTagValue; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.codeStyle.VariableKind; +import com.intellij.psi.javadoc.PsiDocTagValue; import com.intellij.psi.scope.processor.VariablesProcessor; import com.intellij.psi.scope.util.PsiScopesUtil; import com.intellij.psi.search.GlobalSearchScope; @@ -48,16 +48,14 @@ public class ChangeSignatureProcessor extends BaseRefactoringProcessor { private final String myNewVisibility; private String myNewName; private CanonicalTypes.Type myNewType; - private ParameterInfo[] myParameterInfo; private ChangeInfo myChangeInfo; private PsiManager myManager; private PsiElementFactory myFactory; private static final Class[] NORMALIZED_RESOLUTION_CONTEXT_CLASSES = new Class[]{PsiStatement.class, PsiClass.class, PsiFile.class}; - private HashSet myMethodsToBeChanged; private final boolean myGenerateDelegate; - private final PsiMethod[] myPropagateParametersEndPoints; - private final PsiMethod[] myPropagateExceptionsEndPoints; + private final Set myPropagateParametersMethods; + private final Set myPropagateExceptionsMethods; public ChangeSignatureProcessor(Project project, PsiMethod method, @@ -92,12 +90,14 @@ public class ChangeSignatureProcessor extends BaseRefactoringProcessor { CanonicalTypes.Type newType, ParameterInfo[] parameterInfo, ThrownExceptionInfo[] thrownExceptions, - PsiMethod[] propagateParametersEndPoints, - PsiMethod[] propagateExceptionsEndPoints) { + Set propagateParametersMethods, + Set propagateExceptionsMethods) { super(project); myGenerateDelegate = generateDelegate; - myPropagateParametersEndPoints = propagateParametersEndPoints; - myPropagateExceptionsEndPoints = propagateExceptionsEndPoints; + + myPropagateParametersMethods = propagateParametersMethods != null ? propagateParametersMethods : new HashSet(); + myPropagateExceptionsMethods = propagateExceptionsMethods != null ? propagateExceptionsMethods : new HashSet(); + LOG.assertTrue(method.isValid()); if (newVisibility == null) { myNewVisibility = VisibilityUtil.getVisibilityModifier(method.getModifierList()); @@ -106,9 +106,7 @@ public class ChangeSignatureProcessor extends BaseRefactoringProcessor { } myNewName = newName; myNewType = newType; - myParameterInfo = parameterInfo; - - myChangeInfo = new ChangeInfo(myNewVisibility, method, myNewName, myNewType, myParameterInfo, thrownExceptions); + myChangeInfo = new ChangeInfo(myNewVisibility, method, myNewName, myNewType, parameterInfo, thrownExceptions); LOG.assertTrue(myChangeInfo.getMethod().isValid()); } @@ -132,6 +130,18 @@ public class ChangeSignatureProcessor extends BaseRefactoringProcessor { } private void findSimpleUsages(final PsiMethod method, final ArrayList result) { + PsiMethod[] overridingMethods = findSimpleUsagesWithoutParameters(method, result, true, true, true); + findUsagesInCallers (result); + + //Parameter name changes are not propagated + findParametersUsage(method, result, overridingMethods); + } + + private PsiMethod[] findSimpleUsagesWithoutParameters(final PsiMethod method, + final ArrayList result, + boolean isToModifyArgs, + boolean isToThrowExceptions, + boolean isOriginal) { PsiManager manager = method.getManager(); PsiSearchHelper helper = manager.getSearchHelper(); @@ -140,10 +150,10 @@ public class ChangeSignatureProcessor extends BaseRefactoringProcessor { for (int i = 0; i < overridingMethods.length; i++) { PsiMethod overridingMethod = overridingMethods[i]; - result.add(new UsageInfo(overridingMethod)); + result.add(new OverriderUsageInfo(overridingMethod, method, isOriginal, isToModifyArgs, isToThrowExceptions)); } - boolean needToChangeCalls = !myGenerateDelegate && (needToChangeCalls() || myChangeInfo.isVisibilityChanged/*for checking inaccessible*/); + boolean needToChangeCalls = !myGenerateDelegate && (myChangeInfo.isNameChanged || myChangeInfo.isParameterSetOrOrderChanged || myChangeInfo.isExceptionSetOrOrderChanged || myChangeInfo.isVisibilityChanged/*for checking inaccessible*/); if (needToChangeCalls) { List l = new ArrayList(); PsiReference[] refs = helper.findReferencesIncludingOverriding(method, projectScope, true); @@ -155,13 +165,14 @@ public class ChangeSignatureProcessor extends BaseRefactoringProcessor { int parameterCount = method.getParameterList().getParameters().length; for (Iterator iterator = l.iterator(); iterator.hasNext();) { PsiElement ref = iterator.next(); - if (myChangeInfo.isParameterSetOrOrderChanged) { + boolean isToCatchExceptions = isToThrowExceptions && needToCatchExceptions(RefactoringUtil.getEnclosingMethod(ref)); + if (!isToCatchExceptions) { if (RefactoringUtil.isMethodUsage(ref)) { - PsiExpressionList list = RefactoringUtil.getArgumentListByMethodReference((PsiJavaCodeReferenceElement)ref); + PsiExpressionList list = RefactoringUtil.getArgumentListByMethodReference(ref); if (!method.isVarArgs() && list.getExpressions().length != parameterCount) continue; } } - result.add(new UsageInfo(ref)); + result.add(new MethodCallUsageInfo(ref, isToModifyArgs, isToCatchExceptions)); } if (method.isConstructor() && parameterCount == 0) { @@ -178,52 +189,68 @@ public class ChangeSignatureProcessor extends BaseRefactoringProcessor { } } - findParametersUsage(method, result, overridingMethods); - // Conflicts - detectLocalsCollisionsInMethod(method, result); + detectLocalsCollisionsInMethod(method, result, isOriginal); for (int j = 0; j < overridingMethods.length; j++) { final PsiMethod overridingMethod = overridingMethods[j]; - detectLocalsCollisionsInMethod(overridingMethod, result); + detectLocalsCollisionsInMethod(overridingMethod, result, isOriginal); + } + + return overridingMethods; + } + + private void findUsagesInCallers(final ArrayList usages) { + for (Iterator iterator = myPropagateParametersMethods.iterator(); iterator.hasNext();) { + PsiMethod caller = iterator.next(); + usages.add(new CallerUsageInfo(caller, true, myPropagateExceptionsMethods.contains(caller))); + } + for (Iterator iterator = myPropagateExceptionsMethods.iterator(); iterator.hasNext();) { + PsiMethod caller = iterator.next(); + usages.add(new CallerUsageInfo(caller, myPropagateParametersMethods.contains(caller), true)); + } + Set merged = new HashSet(); + merged.addAll(myPropagateParametersMethods); + merged.addAll(myPropagateExceptionsMethods); + for (Iterator iterator = merged.iterator(); iterator.hasNext();) { + final PsiMethod method = iterator.next(); + findSimpleUsagesWithoutParameters(method, usages, myPropagateParametersMethods.contains(method), + myPropagateExceptionsMethods.contains(method), false); } } private boolean needToChangeCalls() { - return myChangeInfo.isNameChanged || myChangeInfo.isParameterSetOrOrderChanged || myChangeInfo.isExceptionSetChanged; + return myChangeInfo.isNameChanged || myChangeInfo.isParameterSetOrOrderChanged || myChangeInfo.isExceptionSetOrOrderChanged; + } + + private boolean needToCatchExceptions(PsiMethod caller) { + return myChangeInfo.isExceptionSetOrOrderChanged && !myPropagateExceptionsMethods.contains(caller); } private void detectLocalsCollisionsInMethod(final PsiMethod method, - final ArrayList result) { - final PsiParameter[] overridingParameters = method.getParameterList().getParameters(); - final Set deletedParameters = - new HashSet(Arrays.asList(overridingParameters)); - - for (int i = 0; i < myParameterInfo.length; i++) { - ParameterInfo parameterInfo = myParameterInfo[i]; - if (parameterInfo.oldParameterIndex >= 0 && - parameterInfo.getName().equals(overridingParameters[parameterInfo.oldParameterIndex].getName())) { - deletedParameters.remove(overridingParameters[parameterInfo.oldParameterIndex]); - } - } - for (int i = 0; i < myParameterInfo.length; i++) { - ParameterInfo parameterInfo = myParameterInfo[i]; + final ArrayList result, + boolean isOriginal) { + final PsiParameter[] parameters = method.getParameterList().getParameters(); + for (int i = 0; i < myChangeInfo.newParms.length; i++) { + ParameterInfo parameterInfo = myChangeInfo.newParms[i]; final int oldParameterIndex = parameterInfo.oldParameterIndex; final String newName = parameterInfo.getName(); if (oldParameterIndex >= 0) { - final PsiParameter parameter = overridingParameters[oldParameterIndex]; - if (!newName.equals(parameter.getName())) { - RenameUtil.visitLocalsCollisions(parameter, newName, method.getBody(), null, new RenameUtil.CollidingVariableVisitor() { - public void visitCollidingElement(final PsiVariable collidingVariable) { - if (!(collidingVariable instanceof PsiField) && !deletedParameters.contains(collidingVariable)) { - result.add(new RenamedParameterCollidesWithLocalUsageInfo(parameter, collidingVariable, method)); + if (isOriginal) { //Name changes take place only in primary method + final PsiParameter parameter = parameters[oldParameterIndex]; + if (!newName.equals(parameter.getName())) { + RenameUtil.visitLocalsCollisions(parameter, newName, method.getBody(), null, new RenameUtil.CollidingVariableVisitor() { + public void visitCollidingElement(final PsiVariable collidingVariable) { + if (!(collidingVariable instanceof PsiField)) { + result.add(new RenamedParameterCollidesWithLocalUsageInfo(parameter, collidingVariable, method)); + } } - } - }); + }); + } } } else { RenameUtil.visitLocalsCollisions(method, newName, method.getBody(), null, new RenameUtil.CollidingVariableVisitor() { public void visitCollidingElement(PsiVariable collidingVariable) { - if (!(collidingVariable instanceof PsiField) && !deletedParameters.contains(collidingVariable)) { + if (!(collidingVariable instanceof PsiField)) { result.add(new NewParameterCollidesWithLocalUsageInfo(collidingVariable, collidingVariable, method)); } } @@ -332,20 +359,21 @@ public class ChangeSignatureProcessor extends BaseRefactoringProcessor { private void askToRemoveCovariantOverriders(Set usages) { if (myManager.getEffectiveLanguageLevel().compareTo(LanguageLevel.JDK_1_5) >= 0) { List covariantOverriderInfos = new ArrayList(); - PsiSubstitutor substitutor = calculateSubstitutor(myChangeInfo.getMethod()); - PsiType type; - try { - type = substitutor.substitute(myChangeInfo.newReturnType.getType(myChangeInfo.getMethod())); - } - catch (IncorrectOperationException e) { - LOG.error(e); - return; - } - for (Iterator iterator = usages.iterator(); iterator.hasNext();) { UsageInfo usageInfo = iterator.next(); - if (usageInfo.getElement() instanceof PsiMethod) { - PsiMethod overrider = (PsiMethod)usageInfo.getElement(); + if (usageInfo instanceof OverriderUsageInfo) { + final OverriderUsageInfo info = (OverriderUsageInfo)usageInfo; + PsiMethod overrider = info.getElement(); + PsiMethod baseMethod = info.getBaseMethod(); + PsiSubstitutor substitutor = calculateSubstitutor(overrider, baseMethod); + PsiType type; + try { + type = substitutor.substitute(myChangeInfo.newReturnType.getType(myChangeInfo.getMethod())); + } + catch (IncorrectOperationException e) { + LOG.error(e); + return; + } if (type.isAssignableFrom(overrider.getReturnType())) { covariantOverriderInfos.add(usageInfo); } @@ -368,8 +396,6 @@ public class ChangeSignatureProcessor extends BaseRefactoringProcessor { protected void performRefactoring(UsageInfo[] usages) { PsiElementFactory factory = myManager.getElementFactory(); - - List postponedUsages = new ArrayList(); try { @@ -381,43 +407,48 @@ public class ChangeSignatureProcessor extends BaseRefactoringProcessor { myChangeInfo.newTypeElement = myChangeInfo.newReturnType.getType(myChangeInfo.getMethod()); } - myMethodsToBeChanged = new HashSet(); - if (myGenerateDelegate) { generateDelegate(); } for (int i = 0; i < usages.length; i++) { UsageInfo usage = usages[i]; - if (!(usage instanceof DefaultConstructorImplicitUsageInfo) && usage.getElement() instanceof PsiMethod) { - myMethodsToBeChanged.add((PsiMethod) usage.getElement()); + if (usage instanceof CallerUsageInfo) { + final CallerUsageInfo callerUsageInfo = (CallerUsageInfo)usage; + processCallerMethod(callerUsageInfo.getMethod(), null, callerUsageInfo.isToInsertParameter(), callerUsageInfo.isToInsertException()); + } else if (usage instanceof OverriderUsageInfo) { + OverriderUsageInfo info = (OverriderUsageInfo)usage; + final PsiMethod method = info.getElement(); + final PsiMethod baseMethod = info.getBaseMethod(); + if (info.isOriginalOverrider()) { + processPrimaryMethod(method, baseMethod, false); + } + else { + processCallerMethod(method, baseMethod, info.isToInsertArgs(), info.isToCatchExceptions()); + } } } - if (myChangeInfo.isExceptionSetOrOrderChanged) { - fixThrowsLists(getChangedExceptionInfo(myChangeInfo)); - } - for (int i = 0; i < usages.length; i++) { UsageInfo usage = usages[i]; - if (!usage.getElement().isValid()) continue; + if (usage.getElement() == null) continue; if (usage instanceof DefaultConstructorImplicitUsageInfo) { - addSuperCall(((DefaultConstructorImplicitUsageInfo) usage).getConstructor()); + final DefaultConstructorImplicitUsageInfo defConstructorUsage = (DefaultConstructorImplicitUsageInfo)usage; + addSuperCall(defConstructorUsage.getConstructor(), defConstructorUsage.getBaseConstructor()); } else if (usage instanceof NoConstructorClassUsageInfo) { addDefaultConstructor(((NoConstructorClassUsageInfo) usage).getPsiClass()); - } else if (usage.getElement() instanceof PsiMethod) { - processMethod((PsiMethod) usage.getElement(), false); } else if (usage.getElement() instanceof PsiJavaCodeReferenceElement) { - if (RefactoringUtil.isMethodUsage(usage.getElement())) { - processMethodUsage((PsiJavaCodeReferenceElement) usage.getElement(), myChangeInfo); + if (usage instanceof MethodCallUsageInfo) { + final MethodCallUsageInfo methodCallInfo = ((MethodCallUsageInfo)usage); + processMethodUsage(methodCallInfo.getElement(), myChangeInfo, methodCallInfo.isToChangeArguments(), methodCallInfo.isToCatchExceptions(), methodCallInfo.getReferencedMethod()); } else { String newName = ((MyParameterUsageInfo) usage).newParameterName; String oldName = ((MyParameterUsageInfo) usage).oldParameterName; processParameterUsage((PsiReferenceExpression) usage.getElement(), oldName, newName); } } else if (usage.getElement() instanceof PsiEnumConstant) { - fixActualArgumentsList(((PsiEnumConstant)usage.getElement()).getArgumentList(), myChangeInfo, false); + fixActualArgumentsList(((PsiEnumConstant)usage.getElement()).getArgumentList(), myChangeInfo, true); } else { postponedUsages.add(usage); } @@ -425,7 +456,7 @@ public class ChangeSignatureProcessor extends BaseRefactoringProcessor { LOG.assertTrue(myChangeInfo.getMethod().isValid()); - processMethod(myChangeInfo.getMethod(), true); + processPrimaryMethod(myChangeInfo.getMethod(), null, true); for (Iterator i = postponedUsages.iterator(); i.hasNext();) { UsageInfo usageInfo = i.next(); @@ -451,11 +482,6 @@ public class ChangeSignatureProcessor extends BaseRefactoringProcessor { } } - fixJavadocsForChangedMethod(myChangeInfo.getMethod()); - for (Iterator iterator = myMethodsToBeChanged.iterator(); iterator.hasNext();) { - PsiMethod method = iterator.next(); - fixJavadocsForChangedMethod(method); - } LOG.assertTrue(myChangeInfo.getMethod().isValid()); } catch (IncorrectOperationException e) { LOG.error(e); @@ -527,17 +553,17 @@ public class ChangeSignatureProcessor extends BaseRefactoringProcessor { defaultConstructor = (PsiMethod) CodeStyleManager.getInstance(myProject).reformat(defaultConstructor); defaultConstructor = (PsiMethod) aClass.add(defaultConstructor); defaultConstructor.getModifierList().setModifierProperty(VisibilityUtil.getVisibilityModifier(aClass.getModifierList()), true); - addSuperCall(defaultConstructor); + addSuperCall(defaultConstructor, null); } else { final PsiElement parent = aClass.getParent(); if (parent instanceof PsiNewExpression) { final PsiExpressionList argumentList = ((PsiNewExpression) parent).getArgumentList(); - fixActualArgumentsList(argumentList, myChangeInfo, false); + fixActualArgumentsList(argumentList, myChangeInfo, true); } } } - private void addSuperCall(PsiMethod constructor) throws IncorrectOperationException { + private void addSuperCall(PsiMethod constructor, PsiMethod callee) throws IncorrectOperationException { PsiExpressionStatement superCall = (PsiExpressionStatement) myFactory.createStatementFromText("super();", constructor); PsiStatement[] statements = constructor.getBody().getStatements(); if (statements.length > 0) { @@ -546,7 +572,7 @@ public class ChangeSignatureProcessor extends BaseRefactoringProcessor { superCall = (PsiExpressionStatement) constructor.getBody().add(superCall); } PsiMethodCallExpression callExpression = (PsiMethodCallExpression) superCall.getExpression(); - processMethodUsage(callExpression.getMethodExpression(), myChangeInfo); + processMethodUsage(callExpression.getMethodExpression(), myChangeInfo, true, false, callee); } private PsiParameter createNewParameter(ParameterInfo newParm, PsiSubstitutor substitutor) throws IncorrectOperationException { @@ -561,41 +587,51 @@ public class ChangeSignatureProcessor extends BaseRefactoringProcessor { return "Changing signature of " + UsageViewUtil.getDescriptiveName(myChangeInfo.getMethod()); } - private void processMethodUsage(PsiJavaCodeReferenceElement ref, ChangeInfo changeInfo) + private void processMethodUsage(PsiElement ref, + ChangeInfo changeInfo, + boolean toChangeArguments, + boolean toCatchExceptions, + PsiMethod callee) throws IncorrectOperationException { if (changeInfo.isNameChanged) { - PsiElement last = ref.getReferenceNameElement(); - if (last instanceof PsiIdentifier && last.getText().equals(changeInfo.oldName)) { - last.replace(changeInfo.newNameIdentifier); - } - } - final PsiExpressionList list = RefactoringUtil.getArgumentListByMethodReference(ref); - - boolean isSuperCall = false; - if (ref instanceof PsiReferenceExpression) { - final PsiExpression qualifierExpression = ((PsiReferenceExpression) ref).getQualifierExpression(); - if (qualifierExpression instanceof PsiSuperExpression) { - - for (Iterator iterator = myMethodsToBeChanged.iterator(); iterator.hasNext();) { - PsiElement element = iterator.next(); - if (PsiTreeUtil.isAncestor(element, ref, false)) { - isSuperCall = true; - break; - } + if (ref instanceof PsiJavaCodeReferenceElement) { + PsiElement last = ((PsiJavaCodeReferenceElement)ref).getReferenceNameElement(); + if (last instanceof PsiIdentifier && last.getText().equals(changeInfo.oldName)) { + last.replace(changeInfo.newNameIdentifier); } } } - fixActualArgumentsList(list, changeInfo, isSuperCall); + final PsiMethod caller = RefactoringUtil.getEnclosingMethod(ref); + if (toChangeArguments) { + final PsiExpressionList list = RefactoringUtil.getArgumentListByMethodReference(ref); + boolean toInsertDefaultValue = !myPropagateParametersMethods.contains(caller); + if (toInsertDefaultValue && ref instanceof PsiReferenceExpression) { + final PsiExpression qualifierExpression = ((PsiReferenceExpression) ref).getQualifierExpression(); + if (qualifierExpression instanceof PsiSuperExpression) { + toInsertDefaultValue = false; + } + } - if (changeInfo.isExceptionSetChanged) { - PsiClassType[] newExceptions = getChangedExceptionInfo(changeInfo); - fixExceptions(ref, newExceptions); + fixActualArgumentsList(list, changeInfo, toInsertDefaultValue); + } + + if (toCatchExceptions) { + if (!(ref instanceof PsiReferenceExpression && ((PsiReferenceExpression)ref).getQualifierExpression() instanceof PsiSuperExpression)) { + if (needToCatchExceptions(caller)) { + PsiClassType[] newExceptions = callee != null ? getCalleeChangedExceptionInfo(callee) : getPrimaryChangedExceptionInfo(changeInfo); + fixExceptions(ref, newExceptions); + } + } } } - private PsiClassType[] getChangedExceptionInfo(ChangeInfo changeInfo) throws IncorrectOperationException { + private PsiClassType[] getCalleeChangedExceptionInfo(final PsiMethod callee) { + return callee.getThrowsList().getReferencedTypes(); //Callee method's throws list is already modified! + } + + private PsiClassType[] getPrimaryChangedExceptionInfo(ChangeInfo changeInfo) throws IncorrectOperationException { PsiClassType[] newExceptions = new PsiClassType[changeInfo.newExceptions.length]; for (int i = 0; i < newExceptions.length; i++) { newExceptions[i] = (PsiClassType)changeInfo.newExceptions[i].myType.getType(myChangeInfo.getMethod()); //context really does not matter here @@ -603,12 +639,9 @@ public class ChangeSignatureProcessor extends BaseRefactoringProcessor { return newExceptions; } - private void fixExceptions(PsiJavaCodeReferenceElement ref, PsiClassType[] newExceptions) throws IncorrectOperationException { - - fixThrowsLists(newExceptions); - + private void fixExceptions(PsiElement ref, PsiClassType[] newExceptions) throws IncorrectOperationException { + //methods' throws lists are already modified, may use ExceptionUtil.collectUnhandledExceptions newExceptions = filterCheckedExceptions(newExceptions); - //Now that methods' throws lists are modified, may use ExceptionUtil.collectUnhandledExceptions PsiElement context = PsiTreeUtil.getParentOfType(ref, new Class[]{PsiTryStatement.class, PsiMethod.class}); if (context instanceof PsiTryStatement) { @@ -686,7 +719,7 @@ public class ChangeSignatureProcessor extends BaseRefactoringProcessor { } } - private void fixThrowsLists(PsiClassType[] newExceptions) throws IncorrectOperationException { + private void fixPrimaryThrowsLists(PsiMethod method, PsiClassType[] newExceptions) throws IncorrectOperationException { PsiElementFactory elementFactory = myManager.getElementFactory(); PsiJavaCodeReferenceElement[] refs = new PsiJavaCodeReferenceElement[newExceptions.length]; for (int i = 0; i < refs.length; i++) { @@ -694,11 +727,7 @@ public class ChangeSignatureProcessor extends BaseRefactoringProcessor { } PsiReferenceList throwsList = elementFactory.createReferenceList(refs); - replaceThrowsList(myChangeInfo.getMethod(), throwsList); - for (Iterator iterator = myMethodsToBeChanged.iterator(); iterator.hasNext();) { - PsiMethod method = iterator.next(); - replaceThrowsList(method, throwsList); - } + replaceThrowsList(method, throwsList); } private void replaceThrowsList(PsiMethod method, PsiReferenceList throwsList) throws IncorrectOperationException { @@ -730,47 +759,66 @@ public class ChangeSignatureProcessor extends BaseRefactoringProcessor { return changeInfo.getMethod().getParameterList().getParameters().length - 1; } - private void fixActualArgumentsList(PsiExpressionList list, ChangeInfo changeInfo, boolean isSuperCall) throws IncorrectOperationException { + //This methods works equally well for primary usages as well as for propagated callers' usages + private void fixActualArgumentsList(PsiExpressionList list, + ChangeInfo changeInfo, + boolean toInsertDefaultValue) throws IncorrectOperationException { final PsiElementFactory factory = list.getManager().getElementFactory(); if (changeInfo.isParameterSetOrOrderChanged) { - final PsiExpression[] args = list.getExpressions(); - final int nonVarargCount = getNonVarargCount(changeInfo, args); - final int varargCount = args.length - nonVarargCount; - - final int newArgsLength; - final int newNonVarargCount; - if (changeInfo.retainsVarargs) { - newNonVarargCount = changeInfo.newParms.length - 1; - newArgsLength = newNonVarargCount + varargCount; - } - else if (changeInfo.obtainsVarags) { - newNonVarargCount = changeInfo.newParms.length - 1; - newArgsLength = newNonVarargCount; - } - else { - newNonVarargCount = changeInfo.newParms.length; - newArgsLength = changeInfo.newParms.length; - } - final PsiExpression[] newArgs = new PsiExpression[newArgsLength]; - for (int i = 0; i < newNonVarargCount; i++) { - final ParameterInfo info = changeInfo.newParms[i]; - final int index = info.oldParameterIndex; - if (index >= 0) { - newArgs[i] = args[index]; - } else { - if (!isSuperCall) { - newArgs[i] = createDefaultValue(factory, info, list); - } else { - newArgs[i] = factory.createExpressionFromText(info.getName(), list); + if (changeInfo.isPropagationEnabled) { + final ParameterInfo[] createdParmsInfo = changeInfo.getCreatedParmsInfoWithoutVarargs(); + for (int i = 0; i < createdParmsInfo.length; i++) { + ParameterInfo info = createdParmsInfo[i]; + PsiExpression newArg; + if (toInsertDefaultValue) { + newArg = createDefaultValue(factory, info, list); } + else { + newArg = factory.createExpressionFromText(info.getName(), list); + } + list.add(newArg); } } - final int newVarargCount = newArgsLength - newNonVarargCount; - LOG.assertTrue(newVarargCount == 0 || newVarargCount == varargCount); - for (int i = 0; i < newVarargCount; i++) { - newArgs[newNonVarargCount + i] = args[nonVarargCount + i]; + else { + final PsiExpression[] args = list.getExpressions(); + final int nonVarargCount = getNonVarargCount(changeInfo, args); + final int varargCount = args.length - nonVarargCount; + + final int newArgsLength; + final int newNonVarargCount; + if (changeInfo.retainsVarargs) { + newNonVarargCount = changeInfo.newParms.length - 1; + newArgsLength = newNonVarargCount + varargCount; + } + else if (changeInfo.obtainsVarags) { + newNonVarargCount = changeInfo.newParms.length - 1; + newArgsLength = newNonVarargCount; + } + else { + newNonVarargCount = changeInfo.newParms.length; + newArgsLength = changeInfo.newParms.length; + } + final PsiExpression[] newArgs = new PsiExpression[newArgsLength]; + for (int i = 0; i < newNonVarargCount; i++) { + final ParameterInfo info = changeInfo.newParms[i]; + final int index = info.oldParameterIndex; + if (index >= 0) { + newArgs[i] = args[index]; + } else { + if (toInsertDefaultValue) { + newArgs[i] = createDefaultValue(factory, info, list); + } else { + newArgs[i] = factory.createExpressionFromText(info.getName(), list); + } + } + } + final int newVarargCount = newArgsLength - newNonVarargCount; + LOG.assertTrue(newVarargCount == 0 || newVarargCount == varargCount); + for (int i = 0; i < newVarargCount; i++) { + newArgs[newNonVarargCount + i] = args[nonVarargCount + i]; + } + ChangeSignatureUtil.synchronizeList(list, Arrays.asList(newArgs), ExpressionList.INSTANCE, changeInfo.toRemoveParm); } - ChangeSignatureUtil.synchronizeList(list, Arrays.asList(newArgs), ExpressionList.INSTANCE, changeInfo.toRemoveParm); } } @@ -814,7 +862,47 @@ public class ChangeSignatureProcessor extends BaseRefactoringProcessor { } } - private void processMethod(PsiMethod method, boolean isOriginal) throws IncorrectOperationException { + private void processCallerMethod(PsiMethod caller, + PsiMethod baseMethod, + boolean toInsertParams, + boolean toInsertThrows) throws IncorrectOperationException { + LOG.assertTrue(toInsertParams || toInsertThrows); + if (toInsertParams) { + List newParameters = new ArrayList(); + newParameters.addAll(Arrays.asList(caller.getParameterList().getParameters())); + final ParameterInfo[] primaryNewParms = myChangeInfo.newParms; + PsiSubstitutor substitutor = baseMethod == null ? PsiSubstitutor.EMPTY : calculateSubstitutor(caller, baseMethod); + for (int i = 0; i < primaryNewParms.length; i++) { + if (primaryNewParms[i].oldParameterIndex < 0) newParameters.add(createNewParameter(primaryNewParms[i], substitutor)); + } + PsiParameter[] arrayed = newParameters.toArray(new PsiParameter[newParameters.size()]); + boolean[] toRemoveParm = new boolean[arrayed.length]; + Arrays.fill(toRemoveParm, false); + resolveParameterVsFieldsConflicts(arrayed, caller, caller.getParameterList(), toRemoveParm); + } + + if (toInsertThrows) { + List newThrowns = new ArrayList(); + final PsiReferenceList throwsList = caller.getThrowsList(); + newThrowns.addAll(Arrays.asList(throwsList.getReferenceElements())); + final ThrownExceptionInfo[] primaryNewExns = myChangeInfo.newExceptions; + for (int i = 0; i < primaryNewExns.length; i++) { + if (primaryNewExns[i].oldIndex < 0) { + final PsiClassType type = (PsiClassType)primaryNewExns[i].createType(caller); + final PsiJavaCodeReferenceElement ref = caller.getManager().getElementFactory().createReferenceElementByType(type); + newThrowns.add(ref); + } + } + PsiJavaCodeReferenceElement[] arrayed = newThrowns.toArray(new PsiJavaCodeReferenceElement[newThrowns.size()]); + boolean[] toRemoveParm = new boolean[arrayed.length]; + Arrays.fill(toRemoveParm, false); + ChangeSignatureUtil.synchronizeList(throwsList, Arrays.asList(arrayed), ThrowsList.INSTANCE, toRemoveParm); + } + } + + private void processPrimaryMethod(PsiMethod method, + PsiMethod baseMethod, + boolean isOriginal) throws IncorrectOperationException { PsiElementFactory factory = method.getManager().getElementFactory(); if (myChangeInfo.isVisibilityChanged) { @@ -826,8 +914,6 @@ public class ChangeSignatureProcessor extends BaseRefactoringProcessor { RefactoringUtil.setVisibility(modifierList, highestVisibility); } - final PsiSubstitutor substitutor = calculateSubstitutor(method); - if (myChangeInfo.isNameChanged) { final EjbMethodRole role = J2EERolesUtil.getEjbRole(method); if (role instanceof EjbImplMethodRole && myChangeInfo.ejbRole instanceof EjbDeclMethodRole) { @@ -852,9 +938,9 @@ public class ChangeSignatureProcessor extends BaseRefactoringProcessor { } } - if (myChangeInfo.isReturnTypeChanged) { - //TODO : normalize brackets! + final PsiSubstitutor substitutor = baseMethod == null ? PsiSubstitutor.EMPTY : calculateSubstitutor(method, baseMethod); + if (myChangeInfo.isReturnTypeChanged) { final PsiType returnType = substitutor.substitute(myChangeInfo.newTypeElement); method.getReturnTypeElement().replace(factory.createTypeElement(returnType)); } @@ -888,30 +974,41 @@ public class ChangeSignatureProcessor extends BaseRefactoringProcessor { } } - List conflictResolvers = new ArrayList(); - final ParameterInfo[] newParmsInfo = myChangeInfo.newParms; - for (int i = 0; i < newParmsInfo.length; i++) { - ParameterInfo parameterInfo = newParmsInfo[i]; - conflictResolvers.add(new FieldConflictsResolver(parameterInfo.getName(), method.getBody())); + resolveParameterVsFieldsConflicts(newParms, method, list, myChangeInfo.toRemoveParm); + fixJavadocsForChangedMethod(method); + if (myChangeInfo.isExceptionSetOrOrderChanged) { + final PsiClassType[] newExceptions = getPrimaryChangedExceptionInfo(myChangeInfo); + fixPrimaryThrowsLists(method, newExceptions); } - ChangeSignatureUtil.synchronizeList(list, Arrays.asList(newParms), ParameterList.INSTANCE, myChangeInfo.toRemoveParm); + } + + private void resolveParameterVsFieldsConflicts(final PsiParameter[] newParms, + final PsiMethod method, + final PsiParameterList list, + boolean[] toRemoveParm) throws IncorrectOperationException { + List conflictResolvers = new ArrayList(); + for (int i = 0; i < newParms.length; i++) { + PsiParameter parameter = newParms[i]; + conflictResolvers.add(new FieldConflictsResolver(parameter.getName(), method.getBody())); + } + ChangeSignatureUtil.synchronizeList(list, Arrays.asList(newParms), ParameterList.INSTANCE, toRemoveParm); for (int i = 0; i < conflictResolvers.size(); i++) { FieldConflictsResolver fieldConflictsResolver = conflictResolvers.get(i); fieldConflictsResolver.fix(); } } - private PsiSubstitutor calculateSubstitutor(PsiMethod method) { + private PsiSubstitutor calculateSubstitutor(PsiMethod derivedMethod, PsiMethod baseMethod) { PsiSubstitutor substitutor; - if (method.getManager().areElementsEquivalent(method, myChangeInfo.getMethod())) { + if (derivedMethod.getManager().areElementsEquivalent(derivedMethod, baseMethod)) { substitutor = PsiSubstitutor.EMPTY; } else { - final PsiClass sourceClass = myChangeInfo.getMethod().getContainingClass(); - final PsiClass containingClass = method.getContainingClass(); - if(sourceClass != null && containingClass != null && InheritanceUtil.isInheritorOrSelf(containingClass, sourceClass, true)) { - final PsiSubstitutor superClassSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(sourceClass, containingClass, PsiSubstitutor.EMPTY); - final MethodSignature superMethodSignature = myChangeInfo.getMethod().getSignature(superClassSubstitutor); - final MethodSignature methodSignature = method.getSignature(PsiSubstitutor.EMPTY); + final PsiClass baseClass = baseMethod.getContainingClass(); + final PsiClass derivedClass = derivedMethod.getContainingClass(); + if(baseClass != null && derivedClass != null && InheritanceUtil.isInheritorOrSelf(derivedClass, baseClass, true)) { + final PsiSubstitutor superClassSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(baseClass, derivedClass, PsiSubstitutor.EMPTY); + final MethodSignature superMethodSignature = baseMethod.getSignature(superClassSubstitutor); + final MethodSignature methodSignature = derivedMethod.getSignature(PsiSubstitutor.EMPTY); final PsiSubstitutor superMethodSubstitutor = MethodSignatureUtil.getSuperMethodSignatureSubstitutor(methodSignature, superMethodSignature); substitutor = superMethodSubstitutor != null ? superMethodSubstitutor : superClassSubstitutor; } else { @@ -1007,4 +1104,11 @@ public class ChangeSignatureProcessor extends BaseRefactoringProcessor { } } + private static class ThrowsList implements ChangeSignatureUtil.ChildrenGenerator { + public static final ThrowsList INSTANCE = new ThrowsList(); + private ThrowsList() {} + public List getChildren(PsiReferenceList throwsList) { + return Arrays.asList(throwsList.getReferenceElements()); + } + } } diff --git a/source/com/intellij/refactoring/changeSignature/MethodCallUsageInfo.java b/source/com/intellij/refactoring/changeSignature/MethodCallUsageInfo.java new file mode 100644 index 000000000000..1e2ab90bae67 --- /dev/null +++ b/source/com/intellij/refactoring/changeSignature/MethodCallUsageInfo.java @@ -0,0 +1,48 @@ +package com.intellij.refactoring.changeSignature; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.psi.*; +import com.intellij.usageView.UsageInfo; + +/** + * @author ven + */ +public class MethodCallUsageInfo extends UsageInfo { + private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.changeSignature.MethodCallUsageInfo"); + private final boolean myToChangeArguments; + private final boolean myToCatchExceptions; + private final PsiMethod myReferencedMethod; + + public boolean isToCatchExceptions() { + return myToCatchExceptions; + } + + public boolean isToChangeArguments() { + return myToChangeArguments; + } + + public MethodCallUsageInfo(final PsiElement ref, boolean isToChangeArguments, boolean isToCatchExceptions) { + super(ref); + myToChangeArguments = isToChangeArguments; + myToCatchExceptions = isToCatchExceptions; + myReferencedMethod = resolveMethod(ref); + } + + private PsiMethod resolveMethod(final PsiElement ref) { + if (ref instanceof PsiEnumConstant) return ((PsiEnumConstant)ref).resolveConstructor(); + PsiElement parent = ref.getParent(); + if (parent instanceof PsiCall) { + return ((PsiCall)parent).resolveMethod(); + } + else if (parent instanceof PsiAnonymousClass) { + return ((PsiNewExpression)parent.getParent()).resolveConstructor(); + } + LOG.assertTrue(false, "Unknown reference"); + + return null; + } + + public PsiMethod getReferencedMethod() { + return myReferencedMethod; + } +} diff --git a/source/com/intellij/refactoring/changeSignature/OverriderUsageInfo.java b/source/com/intellij/refactoring/changeSignature/OverriderUsageInfo.java new file mode 100644 index 000000000000..945f9858d513 --- /dev/null +++ b/source/com/intellij/refactoring/changeSignature/OverriderUsageInfo.java @@ -0,0 +1,43 @@ +package com.intellij.refactoring.changeSignature; + +import com.intellij.psi.PsiMethod; +import com.intellij.usageView.UsageInfo; + +/** + * @author ven + */ +public class OverriderUsageInfo extends UsageInfo { + private final PsiMethod myBaseMethod; + private final boolean myToInsertArgs; + private final boolean myToCatchExceptions; + private boolean myIsOriginalOverrider; + + public OverriderUsageInfo(final PsiMethod method, PsiMethod baseMethod, boolean isOriginalOverrider, + boolean toInsertArgs, boolean toCatchExceptions) { + super(method); + myBaseMethod = baseMethod; + myToInsertArgs = toInsertArgs; + myToCatchExceptions = toCatchExceptions; + myIsOriginalOverrider = isOriginalOverrider; + } + + public PsiMethod getBaseMethod() { + return myBaseMethod; + } + + public PsiMethod getElement() { + return (PsiMethod)super.getElement(); + } + + public boolean isOriginalOverrider() { + return myIsOriginalOverrider; + } + + public boolean isToCatchExceptions() { + return myToCatchExceptions; + } + + public boolean isToInsertArgs() { + return myToInsertArgs; + } +} diff --git a/source/com/intellij/refactoring/changeSignature/inCallers/CallerChooser.java b/source/com/intellij/refactoring/changeSignature/inCallers/CallerChooser.java index 06cc396862f1..70d35f15ad13 100644 --- a/source/com/intellij/refactoring/changeSignature/inCallers/CallerChooser.java +++ b/source/com/intellij/refactoring/changeSignature/inCallers/CallerChooser.java @@ -1,34 +1,37 @@ package com.intellij.refactoring.changeSignature.inCallers; -import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.openapi.ui.Splitter; import com.intellij.openapi.ui.Messages; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.psi.PsiMethod; -import com.intellij.psi.PsiFile; +import com.intellij.openapi.ui.Splitter; import com.intellij.psi.PsiDocumentManager; -import com.intellij.ui.*; -import com.intellij.util.Alarm; -import com.intellij.util.ui.Tree; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiMethod; import com.intellij.refactoring.changeSignature.ChangeSignatureHandler; +import com.intellij.ui.CheckboxTree; +import com.intellij.ui.CheckedTreeNode; +import com.intellij.ui.EditorTextField; +import com.intellij.ui.IdeBorderFactory; +import com.intellij.util.Alarm; +import com.intellij.util.containers.HashSet; +import com.intellij.util.ui.Tree; import javax.swing.*; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; -import javax.swing.tree.*; +import javax.swing.tree.TreePath; +import javax.swing.tree.TreeSelectionModel; import java.awt.*; import java.util.Enumeration; -import java.util.ArrayList; +import java.util.Set; /** * @author ven */ public abstract class CallerChooser extends DialogWrapper { - private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.changeSignature.inCallers.CallerChooser"); PsiMethod myMethod; private EditorTextField myEditorField; private Alarm myAlarm = new Alarm(); @@ -129,20 +132,18 @@ public abstract class CallerChooser extends DialogWrapper { } } - private PsiMethod[] getSelectedMethods () { + private void getSelectedMethods(Set methods) { MethodNode node = myRoot; - ArrayList result = new ArrayList(); - getSelectedMethodsInner(node, result); - return result.toArray(new PsiMethod[result.size()]); + getSelectedMethodsInner(node, methods); + methods.remove(node.getMethod()); } - private void getSelectedMethodsInner(final MethodNode node, final ArrayList methods) { - if (node.isChecked()) { - methods.add(node.getMethod()); - } else { + private void getSelectedMethodsInner(final MethodNode node, final Set allMethods) { + allMethods.add(node.getMethod()); + if (!node.isChecked()) { final Enumeration children = node.children(); while (children.hasMoreElements()) { - getSelectedMethodsInner((MethodNode)children.nextElement(), methods); + getSelectedMethodsInner((MethodNode)children.nextElement(), allMethods); } } } @@ -153,8 +154,8 @@ public abstract class CallerChooser extends DialogWrapper { return; } - final PsiMethod[] selectedMethods = getSelectedMethods(); - LOG.assertTrue(selectedMethods.length > 0); + final Set selectedMethods = new HashSet(); + getSelectedMethods(selectedMethods); callersChosen(selectedMethods); super.doOKAction(); } @@ -170,5 +171,5 @@ public abstract class CallerChooser extends DialogWrapper { return true; } - abstract protected void callersChosen (PsiMethod[] callers); + abstract protected void callersChosen(Set allCallers); } diff --git a/source/com/intellij/refactoring/changeSignature/inCallers/MethodNode.java b/source/com/intellij/refactoring/changeSignature/inCallers/MethodNode.java index 2703cc14061c..528ec0095daa 100644 --- a/source/com/intellij/refactoring/changeSignature/inCallers/MethodNode.java +++ b/source/com/intellij/refactoring/changeSignature/inCallers/MethodNode.java @@ -70,7 +70,8 @@ public class MethodNode extends CheckedTreeNode { List callers = new ArrayList(); for (int i = 0; i < refs.length; i++) { final PsiElement element = refs[i].getElement(); - if (element instanceof PsiReferenceExpression && element.getParent() instanceof PsiMethodCallExpression) { + if (!(element instanceof PsiReferenceExpression) || + !(((PsiReferenceExpression)element).getQualifierExpression() instanceof PsiSuperExpression)) { final PsiElement enclosingContext = PsiTreeUtil.getParentOfType(element, new Class[]{PsiMethod.class, PsiClass.class}); if (enclosingContext instanceof PsiMethod) callers.add((PsiMethod)enclosingContext); } @@ -95,8 +96,10 @@ public class MethodNode extends CheckedTreeNode { ); buffer.append(methodText); - final int style = isEnabled() ? SimpleTextAttributes.STYLE_PLAIN : SimpleTextAttributes.STYLE_STRIKEOUT; - renderer.append(buffer.toString(), new SimpleTextAttributes(style, IdeaUIManager.getTreeForegroung())); + final SimpleTextAttributes attributes = isEnabled() ? + new SimpleTextAttributes(SimpleTextAttributes.STYLE_PLAIN, IdeaUIManager.getTreeForegroung()) : + SimpleTextAttributes.EXCLUDED_ATTRIBUTES; + renderer.append(buffer.toString(), attributes); final String packageName = getPackageName(myMethod.getContainingClass()); renderer.append(" (" + packageName + ")", new SimpleTextAttributes(SimpleTextAttributes.STYLE_ITALIC, Color.GRAY)); diff --git a/source/com/intellij/refactoring/memberPullUp/PullUpHelper.java b/source/com/intellij/refactoring/memberPullUp/PullUpHelper.java index 7d155c06ae7b..cfeb8b868d07 100644 --- a/source/com/intellij/refactoring/memberPullUp/PullUpHelper.java +++ b/source/com/intellij/refactoring/memberPullUp/PullUpHelper.java @@ -479,13 +479,13 @@ public class PullUpHelper { // check default constructor if (constructor == null || constructor.getParameterList().getParameters().length == 0) { RefactoringUtil.visitImplicitSuperConstructorUsages(mySourceClass, new RefactoringUtil.ImplicitConstructorUsageVisitor() { - public void visitConstructor(PsiMethod constructor) { + public void visitConstructor(PsiMethod constructor, PsiMethod baseConstructor) { referencingSubConstructors.add(constructor); } public void visitClassWithoutConstructors(PsiClass aClass) { } - }); + }, myTargetSuperClass); } } diff --git a/source/com/intellij/refactoring/replaceConstructorWithFactory/ReplaceConstructorWithFactoryProcessor.java b/source/com/intellij/refactoring/replaceConstructorWithFactory/ReplaceConstructorWithFactoryProcessor.java index 79934736105f..7f64f2c8f5c2 100644 --- a/source/com/intellij/refactoring/replaceConstructorWithFactory/ReplaceConstructorWithFactoryProcessor.java +++ b/source/com/intellij/refactoring/replaceConstructorWithFactory/ReplaceConstructorWithFactoryProcessor.java @@ -102,7 +102,7 @@ public class ReplaceConstructorWithFactoryProcessor extends BaseRefactoringProce if (myConstructor != null && myConstructor.getParameterList().getParameters().length == 0) { RefactoringUtil.visitImplicitConstructorUsages(getConstructorContainingClass(), new RefactoringUtil.ImplicitConstructorUsageVisitor() { - public void visitConstructor(PsiMethod constructor) { + public void visitConstructor(PsiMethod constructor, PsiMethod baseConstructor) { myNonNewConstructorUsages.add(constructor); } diff --git a/source/com/intellij/refactoring/util/RefactoringUtil.java b/source/com/intellij/refactoring/util/RefactoringUtil.java index 3501b60038d0..1b832a305ef6 100644 --- a/source/com/intellij/refactoring/util/RefactoringUtil.java +++ b/source/com/intellij/refactoring/util/RefactoringUtil.java @@ -394,8 +394,9 @@ public class RefactoringUtil { PsiElement prev = null; while (true) { if (parent instanceof PsiClass) { - if (!(parent instanceof PsiAnonymousClass && ((PsiAnonymousClass)parent).getArgumentList() == prev)) + if (!(parent instanceof PsiAnonymousClass && ((PsiAnonymousClass)parent).getArgumentList() == prev)) { return (PsiClass)parent; + } } prev = parent; parent = parent.getContext(); @@ -406,8 +407,9 @@ public class RefactoringUtil { public static PsiClass getThisResolveClass(final PsiReferenceExpression place) { final ResolveResult resolveResult = place.advancedResolve(false); final PsiElement scope = resolveResult.getCurrentFileResolveScope(); - if (scope instanceof PsiClass) - return (PsiClass) scope; + if (scope instanceof PsiClass) { + return (PsiClass)scope; + } return null; /* PsiElement parent = place.getContext(); @@ -435,6 +437,11 @@ public class RefactoringUtil { return parent instanceof PsiNewExpression ? (PsiNewExpression)parent : null; } + public static final PsiMethod getEnclosingMethod (PsiElement element) { + final PsiElement container = PsiTreeUtil.getParentOfType(element, new Class[]{PsiMethod.class, PsiClass.class}); + return container instanceof PsiMethod ? ((PsiMethod)container) : null; + } + public static void renameVariableReferences(PsiVariable variable, String newName, SearchScope scope) throws IncorrectOperationException { PsiManager manager = variable.getManager(); @@ -764,7 +771,8 @@ public class RefactoringUtil { } } - public static PsiExpressionList getArgumentListByMethodReference(PsiJavaCodeReferenceElement ref) { + public static PsiExpressionList getArgumentListByMethodReference(PsiElement ref) { + if (ref instanceof PsiEnumConstant) return ((PsiEnumConstant)ref).getArgumentList(); PsiElement parent = ref.getParent(); if (parent instanceof PsiCall) { return ((PsiCall)parent).getArgumentList(); @@ -1051,30 +1059,41 @@ public class RefactoringUtil { for (int i = 0; i < inheritors.length; i++) { PsiClass inheritor = inheritors[i]; - visitImplicitSuperConstructorUsages(inheritor, implicitConstructorUsageVistor); + visitImplicitSuperConstructorUsages(inheritor, implicitConstructorUsageVistor, aClass); } } public static void visitImplicitSuperConstructorUsages(PsiClass subClass, - final ImplicitConstructorUsageVisitor implicitConstructorUsageVistor) { + final ImplicitConstructorUsageVisitor implicitConstructorUsageVistor, + PsiClass superClass) { + final PsiMethod baseDefaultConstructor = findDefaultConstructor (superClass); final PsiMethod[] constructors = subClass.getConstructors(); if (constructors.length > 0) { for (int j = 0; j < constructors.length; j++) { PsiMethod constructor = constructors[j]; final PsiStatement[] statements = constructor.getBody().getStatements(); if (statements.length < 1 || !isSuperOrThisCall(statements[0], true, true)) { - implicitConstructorUsageVistor.visitConstructor(constructor); + implicitConstructorUsageVistor.visitConstructor(constructor, baseDefaultConstructor); } } } else { implicitConstructorUsageVistor.visitClassWithoutConstructors(subClass); -// visitImplicitConstructorUsages(inheritor, implicitConstructorUsageVistor); } } + private static PsiMethod findDefaultConstructor(final PsiClass aClass) { + final PsiMethod[] constructors = aClass.getConstructors(); + for (int i = 0; i < constructors.length; i++) { + PsiMethod constructor = constructors[i]; + if (constructor.getParameterList().getParameters().length == 0) return constructor; + } + + return null; + } + public static interface ImplicitConstructorUsageVisitor { - void visitConstructor(PsiMethod constructor); + void visitConstructor(PsiMethod constructor, PsiMethod baseConstructor); void visitClassWithoutConstructors(PsiClass aClass); } diff --git a/source/com/intellij/refactoring/util/usageInfo/DefaultConstructorImplicitUsageInfo.java b/source/com/intellij/refactoring/util/usageInfo/DefaultConstructorImplicitUsageInfo.java index 197f777bc56d..d37cea8e4d3a 100644 --- a/source/com/intellij/refactoring/util/usageInfo/DefaultConstructorImplicitUsageInfo.java +++ b/source/com/intellij/refactoring/util/usageInfo/DefaultConstructorImplicitUsageInfo.java @@ -8,13 +8,19 @@ import com.intellij.usageView.UsageInfo; */ public class DefaultConstructorImplicitUsageInfo extends UsageInfo { private final PsiMethod myOverridingConstructor; + private final PsiMethod myBaseConstructor; - public DefaultConstructorImplicitUsageInfo(PsiMethod overridingConstructor) { + public DefaultConstructorImplicitUsageInfo(PsiMethod overridingConstructor, PsiMethod baseConstructor) { super(overridingConstructor); myOverridingConstructor = overridingConstructor; + myBaseConstructor = baseConstructor; } public PsiMethod getConstructor() { return myOverridingConstructor; } + + public PsiMethod getBaseConstructor() { + return myBaseConstructor; + } } diff --git a/source/com/intellij/refactoring/util/usageInfo/DefaultConstructorUsageCollector.java b/source/com/intellij/refactoring/util/usageInfo/DefaultConstructorUsageCollector.java index 82c31edac5f0..88a85079672e 100644 --- a/source/com/intellij/refactoring/util/usageInfo/DefaultConstructorUsageCollector.java +++ b/source/com/intellij/refactoring/util/usageInfo/DefaultConstructorUsageCollector.java @@ -2,21 +2,22 @@ package com.intellij.refactoring.util.usageInfo; import com.intellij.psi.*; import com.intellij.refactoring.util.RefactoringUtil; +import com.intellij.usageView.UsageInfo; import java.util.ArrayList; public class DefaultConstructorUsageCollector implements RefactoringUtil.ImplicitConstructorUsageVisitor { - private final ArrayList myUsages; + private final ArrayList myUsages; - public void visitConstructor(PsiMethod constructor) { - myUsages.add(new DefaultConstructorImplicitUsageInfo(constructor)); + public void visitConstructor(PsiMethod constructor, PsiMethod baseConstructor) { + myUsages.add(new DefaultConstructorImplicitUsageInfo(constructor, baseConstructor)); } public void visitClassWithoutConstructors(PsiClass aClass) { myUsages.add(new NoConstructorClassUsageInfo(aClass)); } - public DefaultConstructorUsageCollector(ArrayList result) { + public DefaultConstructorUsageCollector(ArrayList result) { myUsages = result; } } diff --git a/testSource/com/intellij/refactoring/ChangeSignatureTest.java b/testSource/com/intellij/refactoring/ChangeSignatureTest.java index 76305aa00bd7..829a30516cb6 100644 --- a/testSource/com/intellij/refactoring/ChangeSignatureTest.java +++ b/testSource/com/intellij/refactoring/ChangeSignatureTest.java @@ -10,9 +10,6 @@ import com.intellij.refactoring.changeSignature.ChangeSignatureProcessor; import com.intellij.refactoring.changeSignature.ParameterInfo; import com.intellij.refactoring.changeSignature.ThrownExceptionInfo; import com.intellij.util.IncorrectOperationException; -import com.intellij.idea.IdeaTestUtil; - -import java.util.Calendar; /** * @author dsl