diff --git a/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/IntroduceParameterObjectProcessor.java b/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/IntroduceParameterObjectProcessor.java index 21bad491f704..39c943eb3020 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/IntroduceParameterObjectProcessor.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/IntroduceParameterObjectProcessor.java @@ -38,6 +38,8 @@ import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.refactoring.MoveDestination; import com.intellij.refactoring.RefactorJBundle; +import com.intellij.refactoring.changeSignature.ChangeInfo; +import com.intellij.refactoring.changeSignature.ChangeSignatureProcessorBase; import com.intellij.refactoring.introduceparameterobject.usageInfo.*; import com.intellij.refactoring.util.FixableUsageInfo; import com.intellij.refactoring.util.FixableUsagesRefactoringProcessor; @@ -77,6 +79,7 @@ public class IntroduceParameterObjectProcessor extends FixableUsagesRefactoringP private final Set paramsNeedingGetters = new HashSet(); private final PsiClass existingClass; private PsiMethod myExistingClassCompatibleConstructor; + private ChangeInfo myChangeInfo; public IntroduceParameterObjectProcessor(String className, String packageName, @@ -179,7 +182,24 @@ public class IntroduceParameterObjectProcessor extends FixableUsagesRefactoringP if (myUseExistingClass && existingClass != null) { myExistingClassCompatibleConstructor = existingClassIsCompatible(existingClass, parameters); } - findUsagesForMethod(method, usages, true); + + final PsiCodeBlock body = method.getBody(); + final String baseParameterName = StringUtil.decapitalize(className); + + final String fixedParamName = + body != null + ? JavaCodeStyleManager.getInstance(myProject).suggestUniqueVariableName(baseParameterName, body.getLBrace(), true) + : JavaCodeStyleManager.getInstance(myProject).propertyNameToVariableName(baseParameterName, VariableKind.PARAMETER); + + myChangeInfo = + new MergeMethodArguments(method, className, packageName, fixedParamName, paramsToMerge, typeParams, keepMethodAsDelegate, + myCreateInnerClass ? method.getContainingClass() : null).createChangeInfo(); + + for (UsageInfo info : ChangeSignatureProcessorBase.findUsages(myChangeInfo)) { + usages.add(new ChangeSignatureUsageWrapper(info)); + } + + findUsagesForMethod(method, usages, fixedParamName); if (myUseExistingClass && existingClass != null && !(paramsNeedingGetters.isEmpty() && paramsNeedingSetters.isEmpty())) { usages.add(new AppendAccessorsUsageInfo(existingClass, myGenerateAccessors, paramsNeedingGetters, paramsNeedingSetters, parameters)); @@ -187,7 +207,7 @@ public class IntroduceParameterObjectProcessor extends FixableUsagesRefactoringP final PsiMethod[] overridingMethods = OverridingMethodsSearch.search(method, true).toArray(PsiMethod.EMPTY_ARRAY); for (PsiMethod siblingMethod : overridingMethods) { - findUsagesForMethod(siblingMethod, usages, false); + findUsagesForMethod(siblingMethod, usages, fixedParamName); } if (myNewVisibility != null) { @@ -195,16 +215,7 @@ public class IntroduceParameterObjectProcessor extends FixableUsagesRefactoringP } } - private void findUsagesForMethod(PsiMethod overridingMethod, List usages, boolean changeSignature) { - final PsiCodeBlock body = overridingMethod.getBody(); - final String baseParameterName = StringUtil.decapitalize(className); - final String fixedParamName = - body != null - ? JavaCodeStyleManager.getInstance(myProject).suggestUniqueVariableName(baseParameterName, body.getLBrace(), true) - : JavaCodeStyleManager.getInstance(myProject).propertyNameToVariableName(baseParameterName, VariableKind.PARAMETER); - - usages.add(new MergeMethodArguments(overridingMethod, className, packageName, fixedParamName, paramsToMerge, typeParams, keepMethodAsDelegate, myCreateInnerClass ? method.getContainingClass() : null, changeSignature)); - + private void findUsagesForMethod(PsiMethod overridingMethod, List usages, String fixedParamName) { final ParamUsageVisitor visitor = new ParamUsageVisitor(overridingMethod, paramsToMerge); overridingMethod.accept(visitor); final Set values = visitor.getParameterUsages(); @@ -261,6 +272,13 @@ public class IntroduceParameterObjectProcessor extends FixableUsagesRefactoringP } } } + List changeSignatureUsages = new ArrayList<>(); + for (UsageInfo info : usageInfos) { + if (info instanceof ChangeSignatureUsageWrapper) { + changeSignatureUsages.add(((ChangeSignatureUsageWrapper)info).getInfo()); + } + } + ChangeSignatureProcessorBase.doChangeSignature(myChangeInfo, changeSignatureUsages.toArray(new UsageInfo[changeSignatureUsages.size()])); } } @@ -537,4 +555,20 @@ public class IntroduceParameterObjectProcessor extends FixableUsagesRefactoringP } } + + private static class ChangeSignatureUsageWrapper extends FixableUsageInfo { + private final UsageInfo myInfo; + + public ChangeSignatureUsageWrapper(UsageInfo info) { + super(info.getElement()); + myInfo = info; + } + + public UsageInfo getInfo() { + return myInfo; + } + + @Override + public void fixUsage() throws IncorrectOperationException {} + } } diff --git a/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/usageInfo/MergeMethodArguments.java b/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/MergeMethodArguments.java similarity index 63% rename from java/java-impl/src/com/intellij/refactoring/introduceparameterobject/usageInfo/MergeMethodArguments.java rename to java/java-impl/src/com/intellij/refactoring/introduceparameterobject/MergeMethodArguments.java index 0aecd58be007..33da7f6253c9 100644 --- a/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/usageInfo/MergeMethodArguments.java +++ b/java/java-impl/src/com/intellij/refactoring/introduceparameterobject/MergeMethodArguments.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,32 +13,29 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.intellij.refactoring.introduceparameterobject.usageInfo; +package com.intellij.refactoring.introduceparameterobject; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.command.CommandProcessor; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleManager; -import com.intellij.psi.impl.source.PsiImmediateClassType; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.util.TypeConversionUtil; -import com.intellij.refactoring.changeSignature.ChangeSignatureProcessor; +import com.intellij.refactoring.changeSignature.ChangeInfo; +import com.intellij.refactoring.changeSignature.JavaChangeInfoImpl; import com.intellij.refactoring.changeSignature.ParameterInfoImpl; -import com.intellij.refactoring.util.FixableUsageInfo; +import com.intellij.refactoring.util.CanonicalTypes; import com.intellij.util.Function; import com.intellij.util.IncorrectOperationException; +import com.intellij.util.VisibilityUtil; import org.jetbrains.annotations.Nullable; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; -@SuppressWarnings({"MethodWithTooManyParameters"}) -public class MergeMethodArguments extends FixableUsageInfo { +public class MergeMethodArguments { private final PsiMethod method; private final PsiClass myContainingClass; - private final boolean myChangeSignature; private final boolean myKeepMethodAsDelegate; private final List typeParams; private final String className; @@ -53,50 +50,45 @@ public class MergeMethodArguments extends FixableUsageInfo { String parameterName, int[] paramsToMerge, List typeParams, - final boolean keepMethodAsDelegate, final PsiClass containingClass, boolean changeSignature) { - super(method); + final boolean keepMethodAsDelegate, + final PsiClass containingClass) { this.paramsToMerge = paramsToMerge; this.packageName = packageName; this.className = className; this.parameterName = parameterName; this.method = method; myContainingClass = containingClass; - myChangeSignature = changeSignature; lastParamIsVararg = method.isVarArgs() && isParameterToMerge(method.getParameterList().getParametersCount() - 1); myKeepMethodAsDelegate = keepMethodAsDelegate; this.typeParams = new ArrayList(typeParams); } - public void fixUsage() throws IncorrectOperationException { + public ChangeInfo createChangeInfo() { final Project project = method.getProject(); final JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project); - final PsiMethod deepestSuperMethod = method.findDeepestSuperMethod(); - final PsiClass psiClass; + PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); + String packageName; if (myContainingClass != null) { - psiClass = myContainingClass.findInnerClassByName(className, false); - } - else { - psiClass = psiFacade.findClass(StringUtil.getQualifiedName(packageName, className), GlobalSearchScope.allScope(project)); - } - assert psiClass != null; - PsiSubstitutor subst = PsiSubstitutor.EMPTY; - if (deepestSuperMethod != null) { - final PsiClass parentClass = deepestSuperMethod.getContainingClass(); - final PsiSubstitutor parentSubstitutor = - TypeConversionUtil.getSuperClassSubstitutor(parentClass, method.getContainingClass(), PsiSubstitutor.EMPTY); - for (int i1 = 0; i1 < psiClass.getTypeParameters().length; i1++) { - final PsiTypeParameter typeParameter = psiClass.getTypeParameters()[i1]; - for (PsiTypeParameter parameter : parentClass.getTypeParameters()) { - if (Comparing.strEqual(typeParameter.getName(), parameter.getName())) { - subst = subst.put(typeParameter, parentSubstitutor.substitute( - new PsiImmediateClassType(parameter, PsiSubstitutor.EMPTY))); - break; - } - } + packageName = myContainingClass.getQualifiedName(); + if (packageName == null) { + packageName = myContainingClass.getName(); } } + else { + packageName = this.packageName; + } + + String text = StringUtil.getQualifiedName(packageName, className); + if (!typeParams.isEmpty()) { + text += "<" + StringUtil.join(typeParams, new Function() { + @Override + public String fun(PsiTypeParameter parameter) { + return parameter.getName(); + } + }, ", ") + ">"; + } + final PsiType classType = factory.createTypeFromText(text, method); final List parametersInfo = new ArrayList(); - final PsiClassType classType = JavaPsiFacade.getElementFactory(project).createType(psiClass, subst); final ParameterInfoImpl mergedParamInfo = new ParameterInfoImpl(-1, parameterName, classType, null) { @Override @@ -117,33 +109,16 @@ public class MergeMethodArguments extends FixableUsageInfo { } parametersInfo.add(firstIncludedIdx == -1 ? 0 : firstIncludedIdx, mergedParamInfo); - final SmartPsiElementPointer meth = SmartPointerManager.getInstance(project).createSmartPsiElementPointer(method); - - final Runnable performChangeSignatureRunnable = new Runnable() { - @Override - public void run() { - final PsiMethod psiMethod = meth.getElement(); - if (psiMethod == null) return; - if (myChangeSignature) { - final ChangeSignatureProcessor changeSignatureProcessor = - new ChangeSignatureProcessor(psiMethod.getProject(), psiMethod, - myKeepMethodAsDelegate, null, psiMethod.getName(), - psiMethod.getReturnType(), - parametersInfo.toArray(new ParameterInfoImpl[parametersInfo.size()])); - changeSignatureProcessor.run(); - } - } - }; - if (ApplicationManager.getApplication().isUnitTestMode()) { - performChangeSignatureRunnable.run(); - } else { - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - CommandProcessor.getInstance().runUndoTransparentAction(performChangeSignatureRunnable); - } - }); - } + PsiType returnType = method.getReturnType(); + return new JavaChangeInfoImpl(VisibilityUtil.getVisibilityModifier(method.getModifierList()), + method, + method.getName(), + returnType != null ? CanonicalTypes.createTypeWrapper(returnType) : null, + parametersInfo.toArray(new ParameterInfoImpl[parametersInfo.size()]), + null, + myKeepMethodAsDelegate, + Collections.emptySet(), + Collections.emptySet()); } private boolean isParameterToMerge(int index) { diff --git a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureProcessorBase.java b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureProcessorBase.java index 4bf5cd412a3c..867e566d5cc6 100644 --- a/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureProcessorBase.java +++ b/platform/lang-impl/src/com/intellij/refactoring/changeSignature/ChangeSignatureProcessorBase.java @@ -71,23 +71,27 @@ public abstract class ChangeSignatureProcessorBase extends BaseRefactoringProces @Override @NotNull protected UsageInfo[] findUsages() { - List infos = new ArrayList(); + return findUsages(myChangeInfo); + } + @NotNull + public static UsageInfo[] findUsages(ChangeInfo changeInfo) { + List infos = new ArrayList(); final ChangeSignatureUsageProcessor[] processors = ChangeSignatureUsageProcessor.EP_NAME.getExtensions(); for (ChangeSignatureUsageProcessor processor : processors) { - ContainerUtil.addAll(infos, processor.findUsages(myChangeInfo)); + ContainerUtil.addAll(infos, processor.findUsages(changeInfo)); } infos = filterUsages(infos); return infos.toArray(new UsageInfo[infos.size()]); } - protected List filterUsages(List infos) { + protected static List filterUsages(List infos) { Map moveRenameInfos = new HashMap(); Set usedElements = new HashSet(); List result = new ArrayList(infos.size() / 2); for (UsageInfo info : infos) { - LOG.assertTrue(info != null, getClass()); + LOG.assertTrue(info != null); PsiElement element = info.getElement(); if (info instanceof MoveRenameUsageInfo) { if (usedElements.contains(element)) continue; @@ -139,14 +143,15 @@ public abstract class ChangeSignatureProcessorBase extends BaseRefactoringProces @Override protected void performRefactoring(@NotNull UsageInfo[] usages) { RefactoringTransaction transaction = getTransaction(); - final RefactoringElementListener elementListener = transaction == null ? null : transaction.getElementListener(myChangeInfo.getMethod()); - final String fqn = CopyReferenceAction.elementToFqn(myChangeInfo.getMethod()); + final ChangeInfo changeInfo = myChangeInfo; + final RefactoringElementListener elementListener = transaction == null ? null : transaction.getElementListener(changeInfo.getMethod()); + final String fqn = CopyReferenceAction.elementToFqn(changeInfo.getMethod()); if (fqn != null) { UndoableAction action = new BasicUndoableAction() { @Override public void undo() { if (elementListener instanceof UndoRefactoringElementListener) { - ((UndoRefactoringElementListener)elementListener).undoElementMovedOrRenamed(myChangeInfo.getMethod(), fqn); + ((UndoRefactoringElementListener)elementListener).undoElementMovedOrRenamed(changeInfo.getMethod(), fqn); } } @@ -157,44 +162,10 @@ public abstract class ChangeSignatureProcessorBase extends BaseRefactoringProces UndoManager.getInstance(myProject).undoableActionPerformed(action); } try { - final ChangeSignatureUsageProcessor[] processors = ChangeSignatureUsageProcessor.EP_NAME.getExtensions(); - - final ResolveSnapshotProvider resolveSnapshotProvider = myChangeInfo.isParameterNamesChanged() ? - VariableInplaceRenamer.INSTANCE.forLanguage(myChangeInfo.getMethod().getLanguage()) : null; - final List snapshots = new ArrayList(); - for (ChangeSignatureUsageProcessor processor : processors) { - if (resolveSnapshotProvider != null) { - processor.registerConflictResolvers(snapshots, resolveSnapshotProvider, usages, myChangeInfo); - } - } - - for (UsageInfo usage : usages) { - for (ChangeSignatureUsageProcessor processor : processors) { - if (processor.processUsage(myChangeInfo, usage, true, usages)) break; - } - } - - LOG.assertTrue(myChangeInfo.getMethod().isValid()); - for (ChangeSignatureUsageProcessor processor : processors) { - if (processor.processPrimaryMethod(myChangeInfo)) break; - } - - for (UsageInfo usage : usages) { - for (ChangeSignatureUsageProcessor processor : processors) { - if (processor.processUsage(myChangeInfo, usage, false, usages)) break; - } - } - - if (!snapshots.isEmpty()) { - for (ParameterInfo parameterInfo : myChangeInfo.getNewParameters()) { - for (ResolveSnapshotProvider.ResolveSnapshot snapshot : snapshots) { - snapshot.apply(parameterInfo.getName()); - } - } - } - final PsiElement method = myChangeInfo.getMethod(); + doChangeSignature(changeInfo, usages); + final PsiElement method = changeInfo.getMethod(); LOG.assertTrue(method.isValid()); - if (elementListener != null && myChangeInfo.isNameChanged()) { + if (elementListener != null && changeInfo.isNameChanged()) { elementListener.elementRenamed(method); } } @@ -203,6 +174,44 @@ public abstract class ChangeSignatureProcessorBase extends BaseRefactoringProces } } + public static void doChangeSignature(ChangeInfo changeInfo, @NotNull UsageInfo[] usages) { + final ChangeSignatureUsageProcessor[] processors = ChangeSignatureUsageProcessor.EP_NAME.getExtensions(); + + final ResolveSnapshotProvider resolveSnapshotProvider = changeInfo.isParameterNamesChanged() ? + VariableInplaceRenamer.INSTANCE.forLanguage(changeInfo.getMethod().getLanguage()) : null; + final List snapshots = new ArrayList(); + for (ChangeSignatureUsageProcessor processor : processors) { + if (resolveSnapshotProvider != null) { + processor.registerConflictResolvers(snapshots, resolveSnapshotProvider, usages, changeInfo); + } + } + + for (UsageInfo usage : usages) { + for (ChangeSignatureUsageProcessor processor : processors) { + if (processor.processUsage(changeInfo, usage, true, usages)) break; + } + } + + LOG.assertTrue(changeInfo.getMethod().isValid()); + for (ChangeSignatureUsageProcessor processor : processors) { + if (processor.processPrimaryMethod(changeInfo)) break; + } + + for (UsageInfo usage : usages) { + for (ChangeSignatureUsageProcessor processor : processors) { + if (processor.processUsage(changeInfo, usage, false, usages)) break; + } + } + + if (!snapshots.isEmpty()) { + for (ParameterInfo parameterInfo : changeInfo.getNewParameters()) { + for (ResolveSnapshotProvider.ResolveSnapshot snapshot : snapshots) { + snapshot.apply(parameterInfo.getName()); + } + } + } + } + @Override protected String getCommandName() { return RefactoringBundle.message("changing.signature.of.0", DescriptiveNameUtil.getDescriptiveName(myChangeInfo.getMethod()));