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.
18 * Created by IntelliJ IDEA.
22 * To change template for new class use
23 * Code Style | Class Templates options (Tools | IDE Options).
25 package com
.intellij
.refactoring
.makeStatic
;
27 import com
.intellij
.openapi
.diagnostic
.Logger
;
28 import com
.intellij
.openapi
.project
.Project
;
29 import com
.intellij
.openapi
.util
.Ref
;
30 import com
.intellij
.openapi
.util
.text
.StringUtil
;
31 import com
.intellij
.psi
.*;
32 import com
.intellij
.psi
.search
.PsiSearchHelper
;
33 import com
.intellij
.psi
.search
.searches
.OverridingMethodsSearch
;
34 import com
.intellij
.psi
.search
.searches
.ReferencesSearch
;
35 import com
.intellij
.psi
.util
.PsiTreeUtil
;
36 import com
.intellij
.psi
.util
.PsiUtil
;
37 import com
.intellij
.refactoring
.BaseRefactoringProcessor
;
38 import com
.intellij
.refactoring
.RefactoringBundle
;
39 import com
.intellij
.refactoring
.ui
.ConflictsDialog
;
40 import com
.intellij
.refactoring
.util
.CommonRefactoringUtil
;
41 import com
.intellij
.refactoring
.util
.ConflictsUtil
;
42 import com
.intellij
.refactoring
.util
.RefactoringUIUtil
;
43 import com
.intellij
.refactoring
.util
.RefactoringUtil
;
44 import com
.intellij
.usageView
.UsageInfo
;
45 import com
.intellij
.usageView
.UsageViewDescriptor
;
46 import com
.intellij
.usageView
.UsageViewUtil
;
47 import com
.intellij
.util
.IncorrectOperationException
;
48 import com
.intellij
.util
.containers
.MultiMap
;
49 import org
.jetbrains
.annotations
.NotNull
;
53 public abstract class MakeMethodOrClassStaticProcessor
<T
extends PsiTypeParameterListOwner
> extends BaseRefactoringProcessor
{
54 private static final Logger LOG
= Logger
.getInstance("#com.intellij.refactoring.makeMethodStatic.MakeMethodStaticProcessor");
57 protected Settings mySettings
;
59 public MakeMethodOrClassStaticProcessor(Project project
,
64 mySettings
= settings
;
67 protected UsageViewDescriptor
createUsageViewDescriptor(UsageInfo
[] usages
) {
68 return new MakeMethodOrClassStaticViewDescriptor(myMember
);
71 protected final boolean preprocessUsages(Ref
<UsageInfo
[]> refUsages
) {
72 UsageInfo
[] usagesIn
= refUsages
.get();
73 if (myPrepareSuccessfulSwingThreadCallback
!= null) {
74 MultiMap
<PsiElement
, String
> conflicts
= getConflictDescriptions(usagesIn
);
75 if (conflicts
.size() > 0) {
76 ConflictsDialog conflictsDialog
= new ConflictsDialog(myProject
, conflicts
);
77 conflictsDialog
.show();
78 if (!conflictsDialog
.isOK()) {
79 if (conflictsDialog
.isShowConflicts()) prepareSuccessful();
83 if(!mySettings
.isChangeSignature()) {
84 refUsages
.set(filterInternalUsages(usagesIn
));
87 refUsages
.set(filterOverriding(usagesIn
));
93 private static UsageInfo
[] filterOverriding(UsageInfo
[] usages
) {
94 ArrayList
<UsageInfo
> result
= new ArrayList
<UsageInfo
>();
95 for (UsageInfo usage
: usages
) {
96 if (!(usage
instanceof OverridingMethodUsageInfo
)) {
100 return result
.toArray(new UsageInfo
[result
.size()]);
103 private static UsageInfo
[] filterInternalUsages(UsageInfo
[] usages
) {
104 ArrayList
<UsageInfo
> result
= new ArrayList
<UsageInfo
>();
105 for (UsageInfo usage
: usages
) {
106 if (!(usage
instanceof InternalUsageInfo
)) {
110 return result
.toArray(new UsageInfo
[result
.size()]);
113 protected MultiMap
<PsiElement
,String
> getConflictDescriptions(UsageInfo
[] usages
) {
114 MultiMap
<PsiElement
, String
> conflicts
= new MultiMap
<PsiElement
, String
>();
115 HashSet
<PsiElement
> processed
= new HashSet
<PsiElement
>();
116 String typeString
= StringUtil
.capitalize(UsageViewUtil
.getType(myMember
));
117 for (UsageInfo usageInfo
: usages
) {
118 if (usageInfo
instanceof InternalUsageInfo
&& !(usageInfo
instanceof SelfUsageInfo
)) {
119 PsiElement referencedElement
= ((InternalUsageInfo
)usageInfo
).getReferencedElement();
120 if (!mySettings
.isMakeClassParameter()) {
121 if (referencedElement
instanceof PsiModifierListOwner
) {
122 if (((PsiModifierListOwner
)referencedElement
).hasModifierProperty(PsiModifier
.STATIC
)) {
127 if (processed
.contains(referencedElement
)) continue;
128 processed
.add(referencedElement
);
129 if (referencedElement
instanceof PsiField
) {
130 PsiField field
= (PsiField
)referencedElement
;
132 if (mySettings
.getNameForField(field
) == null) {
133 String message
= RefactoringBundle
.message("0.uses.non.static.1.which.is.not.passed.as.a.parameter", typeString
,
134 RefactoringUIUtil
.getDescription(field
, true));
135 conflicts
.putValue(field
, message
);
139 String message
= RefactoringBundle
.message("0.uses.1.which.needs.class.instance", typeString
, RefactoringUIUtil
.getDescription(referencedElement
, true));
140 conflicts
.putValue(referencedElement
, message
);
144 if (usageInfo
instanceof OverridingMethodUsageInfo
) {
145 LOG
.assertTrue(myMember
instanceof PsiMethod
);
146 final PsiMethod overridingMethod
= ((PsiMethod
)usageInfo
.getElement());
147 String message
= RefactoringBundle
.message("method.0.is.overridden.by.1", RefactoringUIUtil
.getDescription(myMember
, false),
148 RefactoringUIUtil
.getDescription(overridingMethod
, true));
149 conflicts
.putValue(overridingMethod
, message
);
152 PsiElement element
= usageInfo
.getElement();
153 PsiElement container
= ConflictsUtil
.getContainer(element
);
154 if (processed
.contains(container
)) continue;
155 processed
.add(container
);
156 List
<Settings
.FieldParameter
> fieldParameters
= mySettings
.getParameterOrderList();
157 ArrayList
<PsiField
> inaccessible
= new ArrayList
<PsiField
>();
159 for (final Settings
.FieldParameter fieldParameter
: fieldParameters
) {
160 if (!PsiUtil
.isAccessible(fieldParameter
.field
, element
, null)) {
161 inaccessible
.add(fieldParameter
.field
);
165 if (inaccessible
.isEmpty()) continue;
167 createInaccessibleFieldsConflictDescription(inaccessible
, container
, conflicts
);
173 private static void createInaccessibleFieldsConflictDescription(ArrayList
<PsiField
> inaccessible
, PsiElement container
,
174 MultiMap
<PsiElement
, String
> conflicts
) {
175 if (inaccessible
.size() == 1) {
176 final PsiField field
= inaccessible
.get(0);
177 conflicts
.putValue(field
, RefactoringBundle
.message("field.0.is.not.accessible",
178 CommonRefactoringUtil
.htmlEmphasize(field
.getName()),
179 RefactoringUIUtil
.getDescription(container
, true)));
182 for (int j
= 0; j
< inaccessible
.size(); j
++) {
183 PsiField field
= inaccessible
.get(j
);
184 conflicts
.putValue(field
, RefactoringBundle
.message("field.0.is.not.accessible",
185 CommonRefactoringUtil
.htmlEmphasize(field
.getName()),
186 RefactoringUIUtil
.getDescription(container
, true)));
194 protected UsageInfo
[] findUsages() {
195 ArrayList
<UsageInfo
> result
= new ArrayList
<UsageInfo
>();
196 PsiManager manager
= myMember
.getManager();
197 PsiSearchHelper helper
= manager
.getSearchHelper();
199 result
.addAll(Arrays
.asList(MakeStaticUtil
.findClassRefsInMember(myMember
, true)));
201 if (mySettings
.isReplaceUsages()) {
202 findExternalUsages(result
);
205 if (myMember
instanceof PsiMethod
) {
206 final PsiMethod
[] overridingMethods
=
207 OverridingMethodsSearch
.search((PsiMethod
)myMember
, myMember
.getUseScope(), false).toArray(PsiMethod
.EMPTY_ARRAY
);
208 for (PsiMethod overridingMethod
: overridingMethods
) {
209 if (overridingMethod
!= myMember
) {
210 result
.add(new OverridingMethodUsageInfo(overridingMethod
));
215 return result
.toArray(new UsageInfo
[result
.size()]);
218 protected abstract void findExternalUsages(ArrayList
<UsageInfo
> result
);
220 protected void findExternalReferences(final PsiMethod method
, final ArrayList
<UsageInfo
> result
) {
221 for (PsiReference ref
: ReferencesSearch
.search(method
)) {
222 PsiElement element
= ref
.getElement();
223 PsiElement qualifier
= null;
224 if (element
instanceof PsiReferenceExpression
) {
225 qualifier
= ((PsiReferenceExpression
)element
).getQualifierExpression();
226 if (qualifier
instanceof PsiThisExpression
) qualifier
= null;
228 if (!PsiTreeUtil
.isAncestor(myMember
, element
, true) || qualifier
!= null) {
229 result
.add(new UsageInfo(element
));
234 protected void refreshElements(PsiElement
[] elements
) {
237 //should be called before setting static modifier
238 protected void setupTypeParameterList() throws IncorrectOperationException
{
239 final PsiTypeParameterList list
= myMember
.getTypeParameterList();
241 final PsiTypeParameterList newList
= RefactoringUtil
.createTypeParameterListWithUsedTypeParameters(myMember
);
242 if (newList
!= null) {
243 list
.replace(newList
);
247 protected boolean makeClassParameterFinal(UsageInfo
[] usages
) {
248 for (UsageInfo usage
: usages
) {
249 if (usage
instanceof InternalUsageInfo
) {
250 final InternalUsageInfo internalUsageInfo
= (InternalUsageInfo
)usage
;
251 PsiElement referencedElement
= internalUsageInfo
.getReferencedElement();
252 if (!(referencedElement
instanceof PsiField
)
253 || mySettings
.getNameForField((PsiField
)referencedElement
) == null) {
254 if (internalUsageInfo
.isInsideAnonymous()) {
263 protected static boolean makeFieldParameterFinal(PsiField field
, UsageInfo
[] usages
) {
264 for (UsageInfo usage
: usages
) {
265 if (usage
instanceof InternalUsageInfo
) {
266 final InternalUsageInfo internalUsageInfo
= (InternalUsageInfo
)usage
;
267 PsiElement referencedElement
= internalUsageInfo
.getReferencedElement();
268 if (referencedElement
instanceof PsiField
&& field
.equals(referencedElement
)) {
269 if (internalUsageInfo
.isInsideAnonymous()) {
278 protected String
getCommandName() {
279 return RefactoringBundle
.message("make.static.command", UsageViewUtil
.getDescriptiveName(myMember
));
282 public T
getMember() {
286 public Settings
getSettings() {
290 protected void performRefactoring(UsageInfo
[] usages
) {
291 PsiManager manager
= myMember
.getManager();
292 PsiElementFactory factory
= JavaPsiFacade
.getInstance(manager
.getProject()).getElementFactory();
295 for (UsageInfo usage
: usages
) {
296 if (usage
instanceof SelfUsageInfo
) {
297 changeSelfUsage((SelfUsageInfo
)usage
);
299 else if (usage
instanceof InternalUsageInfo
) {
300 changeInternalUsage((InternalUsageInfo
)usage
, factory
);
303 changeExternalUsage(usage
, factory
);
306 changeSelf(factory
, usages
);
308 catch (IncorrectOperationException ex
) {
309 LOG
.assertTrue(false);
313 protected abstract void changeSelf(PsiElementFactory factory
, UsageInfo
[] usages
) throws IncorrectOperationException
;
315 protected abstract void changeSelfUsage(SelfUsageInfo usageInfo
) throws IncorrectOperationException
;
317 protected abstract void changeInternalUsage(InternalUsageInfo usage
, PsiElementFactory factory
) throws IncorrectOperationException
;
319 protected abstract void changeExternalUsage(UsageInfo usage
, PsiElementFactory factory
) throws IncorrectOperationException
;