update copyright
[fedora-idea.git] / java / java-impl / src / com / intellij / refactoring / changeClassSignature / ChangeClassSignatureProcessor.java
blobeff1ee26c4e0a64413acc8c2b167ad1e670ed44f
1 /*
2 * Copyright 2000-2009 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.changeClassSignature;
18 import com.intellij.history.LocalHistory;
19 import com.intellij.history.LocalHistoryAction;
20 import com.intellij.openapi.diagnostic.Logger;
21 import com.intellij.openapi.project.Project;
22 import com.intellij.psi.*;
23 import com.intellij.psi.search.GlobalSearchScope;
24 import com.intellij.psi.search.searches.ReferencesSearch;
25 import com.intellij.refactoring.BaseRefactoringProcessor;
26 import com.intellij.refactoring.changeSignature.ChangeSignatureUtil;
27 import com.intellij.usageView.UsageInfo;
28 import com.intellij.usageView.UsageViewDescriptor;
29 import com.intellij.util.IncorrectOperationException;
30 import org.jetbrains.annotations.NotNull;
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.List;
36 /**
37 * @author dsl
39 public class ChangeClassSignatureProcessor extends BaseRefactoringProcessor {
40 private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.changeClassSignature.ChangeClassSignatureProcessor");
41 private PsiClass myClass;
42 private final TypeParameterInfo[] myNewSignature;
44 public ChangeClassSignatureProcessor(Project project, PsiClass aClass, TypeParameterInfo[] newSignature) {
45 super(project);
46 myClass = aClass;
47 myNewSignature = newSignature;
50 protected void refreshElements(PsiElement[] elements) {
51 LOG.assertTrue(elements.length == 1);
52 LOG.assertTrue(elements[0] instanceof PsiClass);
53 myClass = (PsiClass)elements[0];
56 protected String getCommandName() {
57 return ChangeClassSignatureDialog.REFACTORING_NAME;
60 protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) {
61 return new ChangeClassSigntaureViewDescriptor(myClass);
64 @NotNull
65 protected UsageInfo[] findUsages() {
66 GlobalSearchScope projectScope = GlobalSearchScope.projectScope(myProject);
67 List<UsageInfo> result = new ArrayList<UsageInfo>();
69 boolean hadTypeParameters = myClass.hasTypeParameters();
70 for (final PsiReference reference : ReferencesSearch.search(myClass, projectScope, false)) {
71 if (reference.getElement() instanceof PsiJavaCodeReferenceElement) {
72 PsiJavaCodeReferenceElement referenceElement = (PsiJavaCodeReferenceElement)reference.getElement();
73 PsiElement parent = referenceElement.getParent();
74 if (parent instanceof PsiTypeElement || parent instanceof PsiNewExpression || parent instanceof PsiAnonymousClass ||
75 parent instanceof PsiReferenceList) {
76 if (!hadTypeParameters || referenceElement.getTypeParameters().length > 0) {
77 result.add(new UsageInfo(referenceElement));
82 return result.toArray(new UsageInfo[result.size()]);
85 protected void performRefactoring(UsageInfo[] usages) {
86 LocalHistoryAction a = LocalHistory.startAction(myProject, getCommandName());
87 try {
88 doRefactoring(usages);
90 catch (IncorrectOperationException e) {
91 LOG.error(e);
93 finally {
94 a.finish();
98 private void doRefactoring(UsageInfo[] usages) throws IncorrectOperationException {
99 final PsiTypeParameter[] typeParameters = myClass.getTypeParameters();
100 boolean[] toRemoveParms = detectRemovedParameters(typeParameters);
102 for (final UsageInfo usage : usages) {
103 LOG.assertTrue(usage.getElement() instanceof PsiJavaCodeReferenceElement);
104 processUsage(usage, typeParameters, toRemoveParms);
107 changeClassSignature(typeParameters, toRemoveParms);
110 private void changeClassSignature(final PsiTypeParameter[] originalTypeParameters, boolean[] toRemoveParms)
111 throws IncorrectOperationException {
112 PsiElementFactory factory = JavaPsiFacade.getInstance(myClass.getProject()).getElementFactory();
113 List<PsiTypeParameter> newTypeParameters = new ArrayList<PsiTypeParameter>();
114 for (final TypeParameterInfo info : myNewSignature) {
115 int oldIndex = info.getOldParameterIndex();
116 if (oldIndex >= 0) {
117 newTypeParameters.add(originalTypeParameters[oldIndex]);
119 else {
120 newTypeParameters.add(factory.createTypeParameterFromText(info.getNewName(), null));
123 ChangeSignatureUtil.synchronizeList(myClass.getTypeParameterList(), newTypeParameters, TypeParameterList.INSTANCE, toRemoveParms);
126 private boolean[] detectRemovedParameters(final PsiTypeParameter[] originaltypeParameters) {
127 final boolean[] toRemoveParms = new boolean[originaltypeParameters.length];
128 Arrays.fill(toRemoveParms, true);
129 for (final TypeParameterInfo info : myNewSignature) {
130 int oldParameterIndex = info.getOldParameterIndex();
131 if (oldParameterIndex >= 0) {
132 toRemoveParms[oldParameterIndex] = false;
135 return toRemoveParms;
138 private void processUsage(final UsageInfo usage, final PsiTypeParameter[] originalTypeParameters, final boolean[] toRemoveParms)
139 throws IncorrectOperationException {
140 PsiElementFactory factory = JavaPsiFacade.getInstance(myClass.getProject()).getElementFactory();
141 PsiJavaCodeReferenceElement referenceElement = (PsiJavaCodeReferenceElement)usage.getElement();
142 PsiSubstitutor usageSubstitutor = determineUsageSubstitutor(referenceElement);
144 PsiReferenceParameterList referenceParameterList = referenceElement.getParameterList();
145 PsiTypeElement[] oldValues = referenceParameterList.getTypeParameterElements();
146 if (oldValues.length != originalTypeParameters.length) return;
147 List<PsiTypeElement> newValues = new ArrayList<PsiTypeElement>();
148 for (final TypeParameterInfo info : myNewSignature) {
149 int oldIndex = info.getOldParameterIndex();
150 if (oldIndex >= 0) {
151 newValues.add(oldValues[oldIndex]);
153 else {
154 PsiType type = info.getDefaultValue().getType(myClass.getLBrace(), PsiManager.getInstance(myProject));
156 PsiTypeElement newValue = factory.createTypeElement(usageSubstitutor.substitute(type));
157 newValues.add(newValue);
160 ChangeSignatureUtil.synchronizeList(referenceParameterList, newValues, ReferenceParameterList.INSTANCE, toRemoveParms);
163 private PsiSubstitutor determineUsageSubstitutor(PsiJavaCodeReferenceElement referenceElement) {
164 PsiType[] typeArguments = referenceElement.getTypeParameters();
165 PsiSubstitutor usageSubstitutor = PsiSubstitutor.EMPTY;
166 PsiTypeParameter[] typeParameters = myClass.getTypeParameters();
167 if (typeParameters.length == typeArguments.length) {
168 for (int i = 0; i < typeParameters.length; i++) {
169 usageSubstitutor = usageSubstitutor.put(typeParameters[i], typeArguments[i]);
172 return usageSubstitutor;
175 private static class ReferenceParameterList implements ChangeSignatureUtil.ChildrenGenerator<PsiReferenceParameterList, PsiTypeElement> {
176 private static final ReferenceParameterList INSTANCE = new ReferenceParameterList();
178 public List<PsiTypeElement> getChildren(PsiReferenceParameterList list) {
179 return Arrays.asList(list.getTypeParameterElements());
183 private static class TypeParameterList implements ChangeSignatureUtil.ChildrenGenerator<PsiTypeParameterList, PsiTypeParameter> {
184 private static final TypeParameterList INSTANCE = new TypeParameterList();
186 public List<PsiTypeParameter> getChildren(PsiTypeParameterList psiTypeParameterList) {
187 return Arrays.asList(psiTypeParameterList.getTypeParameters());