update copyright
[fedora-idea.git] / java / java-impl / src / com / intellij / refactoring / ui / TypeSelectorManagerImpl.java
blob458949c54c4e9783e74c6b11e2964abc2688f7e4
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.ui;
18 import com.intellij.codeInsight.ExpectedTypeInfo;
19 import com.intellij.codeInsight.ExpectedTypeUtil;
20 import com.intellij.codeInsight.ExpectedTypesProvider;
21 import com.intellij.codeInsight.TailType;
22 import com.intellij.openapi.project.Project;
23 import com.intellij.psi.*;
24 import com.intellij.psi.statistics.StatisticsInfo;
25 import com.intellij.psi.statistics.StatisticsManager;
26 import com.intellij.psi.util.PsiUtil;
27 import com.intellij.psi.util.TypeConversionUtil;
28 import com.intellij.refactoring.util.RefactoringHierarchyUtil;
29 import gnu.trove.THashMap;
30 import org.jetbrains.annotations.NotNull;
32 import java.util.*;
34 /**
35 * @author dsl
37 public class TypeSelectorManagerImpl implements TypeSelectorManager {
38 private final PsiType myDefaultType;
39 private final PsiExpression myMainOccurence;
40 private final PsiExpression[] myOccurrences;
41 private final PsiType[] myTypesForMain;
42 private final PsiType[] myTypesForAll;
43 private final boolean myIsOneSuggestion;
44 private TypeSelector myTypeSelector;
45 private final PsiElementFactory myFactory;
46 private ExpectedTypesProvider.ExpectedClassProvider myOccurrenceClassProvider;
47 private ExpectedTypesProvider myExpectedTypesProvider;
49 public TypeSelectorManagerImpl(Project project, PsiType type, PsiExpression mainOccurence, PsiExpression[] occurrences) {
50 myFactory = JavaPsiFacade.getInstance(project).getElementFactory();
51 myDefaultType = type;
52 myMainOccurence = mainOccurence;
53 myOccurrences = occurrences;
54 myExpectedTypesProvider = ExpectedTypesProvider.getInstance(project);
56 myOccurrenceClassProvider = createOccurrenceClassProvider();
57 myTypesForMain = getTypesForMain();
58 myTypesForAll = getTypesForAll(true);
60 myIsOneSuggestion =
61 myTypesForMain.length == 1 && myTypesForAll.length == 1 &&
62 myTypesForAll[0].equals(myTypesForMain[0]);
63 if (myIsOneSuggestion) {
64 myTypeSelector = new TypeSelector(myTypesForAll[0]);
66 else {
67 myTypeSelector = new TypeSelector();
73 public TypeSelectorManagerImpl(Project project, PsiType type, PsiExpression[] occurrences) {
74 this(project, type, occurrences, true);
77 public TypeSelectorManagerImpl(Project project, PsiType type, PsiExpression[] occurrences, boolean areTypesDirected) {
78 myFactory = JavaPsiFacade.getInstance(project).getElementFactory();
79 myDefaultType = type;
80 myMainOccurence = null;
81 myOccurrences = occurrences;
82 myExpectedTypesProvider = ExpectedTypesProvider.getInstance(project);
83 myOccurrenceClassProvider = createOccurrenceClassProvider();
84 myTypesForAll = getTypesForAll(areTypesDirected);
85 myTypesForMain = PsiType.EMPTY_ARRAY;
86 myIsOneSuggestion = myTypesForAll.length == 1;
88 if (myIsOneSuggestion) {
89 myTypeSelector = new TypeSelector(myTypesForAll[0]);
91 else {
92 myTypeSelector = new TypeSelector();
93 setTypesAndPreselect(myTypesForAll);
97 public PsiType[] getTypesForAll() {
98 return myTypesForAll;
101 private ExpectedTypesProvider.ExpectedClassProvider createOccurrenceClassProvider() {
102 final Set<PsiClass> occurrenceClasses = new HashSet<PsiClass>();
103 for (final PsiExpression occurence : myOccurrences) {
104 final PsiType occurrenceType = occurence.getType();
105 final PsiClass aClass = PsiUtil.resolveClassInType(occurrenceType);
106 if (aClass != null) {
107 occurrenceClasses.add(aClass);
110 return new ExpectedTypeUtil.ExpectedClassesFromSetProvider(occurrenceClasses);
113 private PsiType[] getTypesForMain() {
114 final ExpectedTypeInfo[] expectedTypes = myExpectedTypesProvider.getExpectedTypes(myMainOccurence, false, myOccurrenceClassProvider);
115 final ArrayList<PsiType> allowedTypes = new ArrayList<PsiType>();
116 RefactoringHierarchyUtil.processSuperTypes(myDefaultType, new RefactoringHierarchyUtil.SuperTypeVisitor() {
117 public void visitType(PsiType aType) {
118 checkIfAllowed(aType);
121 public void visitClass(PsiClass aClass) {
122 checkIfAllowed(myFactory.createType(aClass));
125 private void checkIfAllowed(PsiType type) {
126 if (expectedTypes != null && expectedTypes.length > 0) {
127 final ExpectedTypeInfo
128 typeInfo = myExpectedTypesProvider.createInfo(type, ExpectedTypeInfo.TYPE_STRICTLY, type, TailType.NONE);
129 for (ExpectedTypeInfo expectedType : expectedTypes) {
130 if (expectedType.intersect(typeInfo).length != 0) {
131 allowedTypes.add(type);
132 break;
136 else {
137 allowedTypes.add(type);
142 ArrayList<PsiType> result = normalizeTypeList(allowedTypes);
143 return result.toArray(new PsiType[result.size()]);
146 private PsiType[] getTypesForAll(final boolean areTypesDirected) {
147 final ArrayList<ExpectedTypeInfo[]> expectedTypesFromAll = new ArrayList<ExpectedTypeInfo[]>();
148 for (PsiExpression occurrence : myOccurrences) {
150 final ExpectedTypeInfo[] expectedTypes = myExpectedTypesProvider.getExpectedTypes(occurrence, false, myOccurrenceClassProvider);
151 if (expectedTypes.length > 0) {
152 expectedTypesFromAll.add(expectedTypes);
156 final ArrayList<PsiType> allowedTypes = new ArrayList<PsiType>();
157 RefactoringHierarchyUtil.processSuperTypes(myDefaultType, new RefactoringHierarchyUtil.SuperTypeVisitor() {
158 public void visitType(PsiType aType) {
159 checkIfAllowed(aType);
162 public void visitClass(PsiClass aClass) {
163 checkIfAllowed(myFactory.createType(aClass));
166 private void checkIfAllowed(PsiType type) {
167 NextInfo:
168 for (ExpectedTypeInfo[] expectedTypes : expectedTypesFromAll) {
169 for (final ExpectedTypeInfo info : expectedTypes) {
170 if (ExpectedTypeUtil.matches(type, info)) continue NextInfo;
172 return;
174 allowedTypes.add(type);
178 final ArrayList<PsiType> result = normalizeTypeList(allowedTypes);
179 if (!areTypesDirected) {
180 Collections.reverse(result);
182 return result.toArray(new PsiType[result.size()]);
185 private ArrayList<PsiType> normalizeTypeList(final ArrayList<PsiType> typeList) {
186 ArrayList<PsiType> result = new ArrayList<PsiType>();
187 TypeListCreatingVisitor visitor = new TypeListCreatingVisitor(result, myFactory);
188 for (PsiType psiType : typeList) {
189 visitor.visitType(psiType);
192 for (int index = 0; index < result.size(); index++) {
193 PsiType psiType = result.get(index);
194 if (psiType.equals(myDefaultType)) {
195 result.remove(index);
196 break;
200 final PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(myDefaultType);
201 if (unboxedType != null) {
202 result.remove(unboxedType);
203 result.add(0, unboxedType);
205 result.add(0, myDefaultType);
206 return result;
209 public void setAllOccurences(boolean allOccurences) {
210 if (myIsOneSuggestion) return;
211 setTypesAndPreselect(allOccurences ? myTypesForAll : myTypesForMain);
214 private void setTypesAndPreselect(PsiType[] types) {
215 myTypeSelector.setTypes(types);
217 Map<String, PsiType> map = new THashMap<String, PsiType>();
218 for (final PsiType type : types) {
219 map.put(serialize(type), type);
222 for (StatisticsInfo info : StatisticsManager.getInstance().getAllValues(getStatsKey())) {
223 final PsiType candidate = map.get(info.getValue());
224 if (candidate != null && StatisticsManager.getInstance().getUseCount(info) > 0) {
225 myTypeSelector.selectType(candidate);
226 return;
231 public boolean isSuggestedType(final String fqName) {
232 for(PsiType type: myTypesForAll) {
233 if (type.getCanonicalText().equals(fqName)) {
234 return true;
238 for(PsiType type: myTypesForMain) {
239 if (type.getCanonicalText().equals(fqName)) {
240 return true;
244 return false;
247 public void typeSelected(@NotNull PsiType type) {
248 StatisticsManager.getInstance().incUseCount(new StatisticsInfo(getStatsKey(), serialize(type)));
251 private String getStatsKey() {
252 return "IntroduceVariable##" + serialize(myDefaultType);
255 private String serialize(PsiType type) {
256 return TypeConversionUtil.erasure(type).getCanonicalText();
259 public TypeSelector getTypeSelector() {
260 return myTypeSelector;