ability to change name of method to any string constant. Detection of incorrect usages
[idea/community.git] / plugins / groovy / src / org / jetbrains / plugins / groovy / refactoring / changeSignature / GrChangeSignatureProcessor.java
1 /*
2  * Copyright 2000-2010 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 package org.jetbrains.plugins.groovy.refactoring.changeSignature;
17
18 import com.intellij.openapi.diagnostic.Logger;
19 import com.intellij.openapi.project.Project;
20 import com.intellij.openapi.util.Ref;
21 import com.intellij.psi.PsiElement;
22 import com.intellij.psi.PsiMethod;
23 import com.intellij.refactoring.BaseRefactoringProcessor;
24 import com.intellij.refactoring.changeSignature.ChangeSignatureUsageProcessor;
25 import com.intellij.refactoring.changeSignature.ChangeSignatureViewDescriptor;
26 import com.intellij.refactoring.changeSignature.PossiblyIncorrectUsage;
27 import com.intellij.refactoring.rename.RenameUtil;
28 import com.intellij.refactoring.ui.ConflictsDialog;
29 import com.intellij.refactoring.util.MoveRenameUsageInfo;
30 import com.intellij.usageView.UsageInfo;
31 import com.intellij.usageView.UsageViewDescriptor;
32 import com.intellij.usageView.UsageViewUtil;
33 import com.intellij.util.containers.HashSet;
34 import com.intellij.util.containers.MultiMap;
35 import com.intellij.util.containers.hash.HashMap;
36 import org.jetbrains.annotations.NotNull;
37 import org.jetbrains.plugins.groovy.refactoring.GroovyRefactoringBundle;
38
39 import java.util.*;
40
41 /**
42  * @author Maxim.Medvedev
43  */
44 public class GrChangeSignatureProcessor extends BaseRefactoringProcessor {
45   public static final Logger LOG =
46     Logger.getInstance("#org.jetbrains.plugins.groovy.refactoring.changeSignature.GrChangeSignatureProcessor");
47   private final GrChangeInfoImpl myChangeInfo;
48
49   //private
50
51   public GrChangeSignatureProcessor(Project project, GrChangeInfoImpl changeInfo) {
52     super(project);
53     myChangeInfo = changeInfo;
54   }
55
56   @Override
57   protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) {
58     return new ChangeSignatureViewDescriptor(myChangeInfo.getMethod());
59   }
60
61   @NotNull
62   @Override
63   protected UsageInfo[] findUsages() {
64     List<UsageInfo> infos = new ArrayList<UsageInfo>();
65
66     final ChangeSignatureUsageProcessor[] processors = ChangeSignatureUsageProcessor.EP_NAME.getExtensions();
67     for (ChangeSignatureUsageProcessor processor : processors) {
68       infos.addAll(Arrays.asList(processor.findUsages(myChangeInfo)));
69     }
70
71     infos = filterUsages(infos);
72     return infos.toArray(new UsageInfo[infos.size()]);
73   }
74
75   private static List<UsageInfo> filterUsages(List<UsageInfo> infos) {
76     Map<PsiElement, MoveRenameUsageInfo> moveRenameInfos = new HashMap<PsiElement, MoveRenameUsageInfo>();
77     Set<PsiElement> usedElements = new com.intellij.util.containers.hash.HashSet<PsiElement>();
78
79     List<UsageInfo> result = new ArrayList<UsageInfo>(infos.size() / 2);
80     for (UsageInfo info : infos) {
81       PsiElement element = info.getElement();
82       if (info instanceof MoveRenameUsageInfo) {
83         if (usedElements.contains(element)) continue;
84         moveRenameInfos.put(element, (MoveRenameUsageInfo)info);
85       }
86       else {
87         moveRenameInfos.remove(element);
88         usedElements.add(element);
89         if (!(info instanceof PossiblyIncorrectUsage) || ((PossiblyIncorrectUsage)info).isCorrect()) {
90           result.add(info);
91         }
92       }
93     }
94     result.addAll(moveRenameInfos.values());
95     return result;
96   }
97
98   @Override
99   protected void refreshElements(PsiElement[] elements) {
100     boolean condition = elements.length == 1 && elements[0] instanceof PsiMethod;
101     LOG.assertTrue(condition);
102     myChangeInfo.updateMethod((PsiMethod)elements[0]);
103   }
104
105   @Override
106   protected void performRefactoring(UsageInfo[] usages) {
107     for (UsageInfo usage : usages) {
108       for (ChangeSignatureUsageProcessor processor : ChangeSignatureUsageProcessor.EP_NAME.getExtensions()) {
109         if (processor.processUsage(myChangeInfo, usage, true, usages)) break;
110       }
111     }
112     changeMethod();
113     for (UsageInfo usage : usages) {
114       for (ChangeSignatureUsageProcessor processor : ChangeSignatureUsageProcessor.EP_NAME.getExtensions()) {
115         if (processor.processUsage(myChangeInfo, usage, false, usages)) break;
116       }
117     }
118   }
119
120   private void changeMethod() {
121     for (ChangeSignatureUsageProcessor processor : ChangeSignatureUsageProcessor.EP_NAME.getExtensions()) {
122       if (processor.processPrimaryMethod(myChangeInfo)) break;
123     }
124   }
125
126   @Override
127   protected String getCommandName() {
128     return GroovyRefactoringBundle.message("changing.signature.of.0", UsageViewUtil.getDescriptiveName(myChangeInfo.getMethod()));
129   }
130
131   @Override
132   protected boolean preprocessUsages(Ref<UsageInfo[]> refUsages) {
133     MultiMap<PsiElement, String> conflictDescriptions = new MultiMap<PsiElement, String>();
134     for (ChangeSignatureUsageProcessor usageProcessor : ChangeSignatureUsageProcessor.EP_NAME.getExtensions()) {
135       final MultiMap<PsiElement, String> conflicts = usageProcessor.findConflicts(myChangeInfo, refUsages);
136       for (PsiElement key : conflicts.keySet()) {
137         Collection<String> collection = conflictDescriptions.get(key);
138         if (collection.size() == 0) collection = new HashSet<String>();
139         collection.addAll(conflicts.get(key));
140         conflictDescriptions.put(key, collection);
141       }
142     }
143
144     final UsageInfo[] usagesIn = refUsages.get();
145     RenameUtil.addConflictDescriptions(usagesIn, conflictDescriptions);
146     Set<UsageInfo> usagesSet = new HashSet<UsageInfo>(Arrays.asList(usagesIn));
147     RenameUtil.removeConflictUsages(usagesSet);
148     if (!conflictDescriptions.isEmpty()) {
149       ConflictsDialog dialog = new ConflictsDialog(myProject, conflictDescriptions, new Runnable() {
150         public void run() {
151           execute(usagesIn);
152         }
153       });
154       dialog.show();
155       if (!dialog.isOK()) {
156         if (dialog.isShowConflicts()) prepareSuccessful();
157         return false;
158       }
159     }
160     refUsages.set(usagesSet.toArray(new UsageInfo[usagesSet.size()]));
161     prepareSuccessful();
162     return true;
163   }
164
165   @Override
166   protected boolean isPreviewUsages(UsageInfo[] usages) {
167     for (ChangeSignatureUsageProcessor processor : ChangeSignatureUsageProcessor.EP_NAME.getExtensions()) {
168       if (processor.shouldPreviewUsages(myChangeInfo, usages)) return true;
169     }
170     return super.isPreviewUsages(usages);
171   }
172 }