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
;
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();
52 myMainOccurence
= mainOccurence
;
53 myOccurrences
= occurrences
;
54 myExpectedTypesProvider
= ExpectedTypesProvider
.getInstance(project
);
56 myOccurrenceClassProvider
= createOccurrenceClassProvider();
57 myTypesForMain
= getTypesForMain();
58 myTypesForAll
= getTypesForAll(true);
61 myTypesForMain
.length
== 1 && myTypesForAll
.length
== 1 &&
62 myTypesForAll
[0].equals(myTypesForMain
[0]);
63 if (myIsOneSuggestion
) {
64 myTypeSelector
= new TypeSelector(myTypesForAll
[0]);
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();
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]);
92 myTypeSelector
= new TypeSelector();
93 setTypesAndPreselect(myTypesForAll
);
97 public PsiType
[] getTypesForAll() {
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
);
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
) {
168 for (ExpectedTypeInfo
[] expectedTypes
: expectedTypesFromAll
) {
169 for (final ExpectedTypeInfo info
: expectedTypes
) {
170 if (ExpectedTypeUtil
.matches(type
, info
)) continue NextInfo
;
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
);
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
);
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
);
231 public boolean isSuggestedType(final String fqName
) {
232 for(PsiType type
: myTypesForAll
) {
233 if (type
.getCanonicalText().equals(fqName
)) {
238 for(PsiType type
: myTypesForMain
) {
239 if (type
.getCanonicalText().equals(fqName
)) {
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
;