blob: 29596b7b8456f1b77eef39faedcfdc2cadd81cda [file] [log] [blame]
/*
* Copyright 2000-2010 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.refactoring.changeSignature;
import com.intellij.ide.actions.CopyReferenceAction;
import com.intellij.lang.findUsages.DescriptiveNameUtil;
import com.intellij.openapi.command.undo.BasicUndoableAction;
import com.intellij.openapi.command.undo.UndoManager;
import com.intellij.openapi.command.undo.UndoableAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiManager;
import com.intellij.refactoring.BaseRefactoringProcessor;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.listeners.RefactoringElementListener;
import com.intellij.refactoring.listeners.RefactoringEventData;
import com.intellij.refactoring.listeners.UndoRefactoringElementListener;
import com.intellij.refactoring.listeners.impl.RefactoringTransaction;
import com.intellij.refactoring.rename.ResolveSnapshotProvider;
import com.intellij.refactoring.rename.inplace.VariableInplaceRenamer;
import com.intellij.refactoring.util.MoveRenameUsageInfo;
import com.intellij.usageView.UsageInfo;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.hash.HashMap;
import com.intellij.util.containers.hash.HashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author Maxim.Medvedev
*/
public abstract class ChangeSignatureProcessorBase extends BaseRefactoringProcessor {
private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.changeSignature.ChangeSignatureProcessorBase");
protected final ChangeInfo myChangeInfo;
protected final PsiManager myManager;
protected ChangeSignatureProcessorBase(Project project, ChangeInfo changeInfo) {
super(project);
myChangeInfo = changeInfo;
myManager = PsiManager.getInstance(project);
}
protected ChangeSignatureProcessorBase(Project project, @Nullable Runnable prepareSuccessfulCallback, ChangeInfo changeInfo) {
super(project, prepareSuccessfulCallback);
myChangeInfo = changeInfo;
myManager = PsiManager.getInstance(project);
}
@Override
@NotNull
protected UsageInfo[] findUsages() {
List<UsageInfo> infos = new ArrayList<UsageInfo>();
final ChangeSignatureUsageProcessor[] processors = ChangeSignatureUsageProcessor.EP_NAME.getExtensions();
for (ChangeSignatureUsageProcessor processor : processors) {
ContainerUtil.addAll(infos, processor.findUsages(myChangeInfo));
}
infos = filterUsages(infos);
return infos.toArray(new UsageInfo[infos.size()]);
}
protected List<UsageInfo> filterUsages(List<UsageInfo> infos) {
Map<PsiElement, MoveRenameUsageInfo> moveRenameInfos = new HashMap<PsiElement, MoveRenameUsageInfo>();
Set<PsiElement> usedElements = new HashSet<PsiElement>();
List<UsageInfo> result = new ArrayList<UsageInfo>(infos.size() / 2);
for (UsageInfo info : infos) {
LOG.assertTrue(info != null, getClass());
PsiElement element = info.getElement();
if (info instanceof MoveRenameUsageInfo) {
if (usedElements.contains(element)) continue;
moveRenameInfos.put(element, (MoveRenameUsageInfo)info);
}
else {
moveRenameInfos.remove(element);
usedElements.add(element);
if (!(info instanceof PossiblyIncorrectUsage) || ((PossiblyIncorrectUsage)info).isCorrect()) {
result.add(info);
}
}
}
result.addAll(moveRenameInfos.values());
return result;
}
@Override
protected boolean isPreviewUsages(UsageInfo[] usages) {
for (ChangeSignatureUsageProcessor processor : ChangeSignatureUsageProcessor.EP_NAME.getExtensions()) {
if (processor.shouldPreviewUsages(myChangeInfo, usages)) return true;
}
return super.isPreviewUsages(usages);
}
@Nullable
@Override
protected String getRefactoringId() {
return "refactoring.changeSignature";
}
@Nullable
@Override
protected RefactoringEventData getBeforeData() {
RefactoringEventData data = new RefactoringEventData();
data.addElement(getChangeInfo().getMethod());
return data;
}
@Nullable
@Override
protected RefactoringEventData getAfterData(UsageInfo[] usages) {
RefactoringEventData data = new RefactoringEventData();
data.addElement(getChangeInfo().getMethod());
return data;
}
@Override
protected void performRefactoring(UsageInfo[] usages) {
RefactoringTransaction transaction = getTransaction();
final RefactoringElementListener elementListener = transaction == null ? null : transaction.getElementListener(myChangeInfo.getMethod());
final String fqn = CopyReferenceAction.elementToFqn(myChangeInfo.getMethod());
if (fqn != null) {
UndoableAction action = new BasicUndoableAction() {
@Override
public void undo() {
if (elementListener instanceof UndoRefactoringElementListener) {
((UndoRefactoringElementListener)elementListener).undoElementMovedOrRenamed(myChangeInfo.getMethod(), fqn);
}
}
@Override
public void redo() {
}
};
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<ResolveSnapshotProvider.ResolveSnapshot> snapshots = new ArrayList<ResolveSnapshotProvider.ResolveSnapshot>();
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();
LOG.assertTrue(method.isValid());
if (elementListener != null && myChangeInfo.isNameChanged()) {
elementListener.elementRenamed(method);
}
}
catch (IncorrectOperationException e) {
LOG.error(e);
}
}
@Override
protected String getCommandName() {
return RefactoringBundle.message("changing.signature.of.0", DescriptiveNameUtil.getDescriptiveName(myChangeInfo.getMethod()));
}
public ChangeInfo getChangeInfo() {
return myChangeInfo;
}
}