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
;
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
) {
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
);
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());
88 doRefactoring(usages
);
90 catch (IncorrectOperationException e
) {
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();
117 newTypeParameters
.add(originalTypeParameters
[oldIndex
]);
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();
151 newValues
.add(oldValues
[oldIndex
]);
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());