update copyright
[fedora-idea.git] / java / java-impl / src / com / intellij / refactoring / makeStatic / MakeMethodOrClassStaticProcessor.java
blobf821f743cd5a0368dc594706073f62461d0a9372
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.
18 * Created by IntelliJ IDEA.
19 * User: dsl
20 * Date: 16.04.2002
21 * Time: 15:37:30
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;
51 import java.util.*;
53 public abstract class MakeMethodOrClassStaticProcessor<T extends PsiTypeParameterListOwner> extends BaseRefactoringProcessor {
54 private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.makeMethodStatic.MakeMethodStaticProcessor");
56 protected T myMember;
57 protected Settings mySettings;
59 public MakeMethodOrClassStaticProcessor(Project project,
60 T member,
61 Settings settings) {
62 super(project);
63 myMember = member;
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();
80 return false;
83 if(!mySettings.isChangeSignature()) {
84 refUsages.set(filterInternalUsages(usagesIn));
87 refUsages.set(filterOverriding(usagesIn));
89 prepareSuccessful();
90 return true;
93 private static UsageInfo[] filterOverriding(UsageInfo[] usages) {
94 ArrayList<UsageInfo> result = new ArrayList<UsageInfo>();
95 for (UsageInfo usage : usages) {
96 if (!(usage instanceof OverridingMethodUsageInfo)) {
97 result.add(usage);
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)) {
107 result.add(usage);
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)) {
123 continue;
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);
138 else {
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);
151 else {
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);
170 return 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)));
180 } else {
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)));
193 @NotNull
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();
240 assert list != null;
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()) {
255 return true;
260 return false;
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()) {
270 return true;
275 return false;
278 protected String getCommandName() {
279 return RefactoringBundle.message("make.static.command", UsageViewUtil.getDescriptiveName(myMember));
282 public T getMember() {
283 return myMember;
286 public Settings getSettings() {
287 return mySettings;
290 protected void performRefactoring(UsageInfo[] usages) {
291 PsiManager manager = myMember.getManager();
292 PsiElementFactory factory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory();
294 try {
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);
302 else {
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;