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
.typeCook
;
18 import com
.intellij
.openapi
.diagnostic
.Logger
;
19 import com
.intellij
.psi
.*;
20 import com
.intellij
.psi
.search
.GlobalSearchScope
;
21 import com
.intellij
.psi
.util
.PsiUtil
;
22 import com
.intellij
.refactoring
.typeCook
.deductive
.PsiTypeVariableFactory
;
23 import com
.intellij
.util
.IncorrectOperationException
;
25 import java
.util
.HashSet
;
29 * Created by IntelliJ IDEA.
33 * To change this template use Options | File Templates.
36 private static final Logger LOG
= Logger
.getInstance("#com.intellij.refactoring.typeCook.Util");
38 public static PsiType
createArrayType(PsiType theType
, int level
) {
40 theType
= theType
.createArrayType();
46 public static PsiClassType
.ClassResolveResult
resolveType(PsiType type
) {
47 final PsiClassType
.ClassResolveResult resolveResult
= PsiUtil
.resolveGenericsClassInType(type
);
48 final PsiClass aClass
= resolveResult
.getElement();
49 if (aClass
instanceof PsiAnonymousClass
) {
50 final PsiClassType baseClassType
= ((PsiAnonymousClass
)aClass
).getBaseClassType();
51 return resolveType(resolveResult
.getSubstitutor().substitute(baseClassType
));
56 public static PsiType
normalize(PsiType t
, boolean objectBottom
) {
57 if (t
instanceof PsiArrayType
) {
58 PsiType normType
= normalize(((PsiArrayType
)t
).getComponentType(), objectBottom
);
60 return normType
== null ?
null : normType
.createArrayType();
62 else if (t
instanceof PsiClassType
) {
63 PsiClassType
.ClassResolveResult result
= resolveType(t
);
69 PsiClass aclass
= result
.getElement();
70 PsiSubstitutor subst
= result
.getSubstitutor();
71 PsiManager manager
= aclass
.getManager();
73 PsiSubstitutor newbst
= PsiSubstitutor
.EMPTY
;
74 boolean anyBottom
= false;
75 for (PsiTypeParameter typeParameter
: PsiUtil
.typeParametersIterable(aclass
)) {
76 PsiType p
= subst
.substitute(typeParameter
);
79 PsiType pp
= normalize(p
, objectBottom
);
85 if (pp
== Bottom
.BOTTOM
|| (objectBottom
&& pp
.getCanonicalText().equals("java.lang.Object"))) {
89 newbst
= newbst
.put(typeParameter
, pp
);
96 if (anyBottom
|| newbst
== PsiSubstitutor
.EMPTY
) {
97 newbst
= JavaPsiFacade
.getInstance(manager
.getProject()).getElementFactory().createRawSubstitutor(aclass
);
100 return JavaPsiFacade
.getInstance(manager
.getProject()).getElementFactory().createType(aclass
, newbst
);
107 public static boolean isRaw(PsiType t
, final Settings settings
) {
108 return isRaw(t
, settings
, true);
111 private static boolean isRaw(PsiType t
, final Settings settings
, final boolean upper
) {
112 if (t
instanceof PsiClassType
) {
113 final PsiClassType
.ClassResolveResult resolveResult
= resolveType(t
);
115 if (resolveResult
.getElement() == null) {
119 if (PsiClassType
.isRaw(resolveResult
)) {
123 final PsiSubstitutor subst
= resolveResult
.getSubstitutor();
124 final PsiClass element
= resolveResult
.getElement();
125 final PsiManager manager
= element
.getManager();
127 if (settings
.cookObjects() && upper
&&
128 t
.equals(PsiType
.getJavaLangObject(manager
, GlobalSearchScope
.allScope(manager
.getProject())))) {
132 for (PsiTypeParameter parameter
: PsiUtil
.typeParametersIterable(element
)) {
133 final PsiType actual
= subst
.substitute(parameter
);
134 if (isRaw(actual
, settings
, false)) return true;
139 else if (t
instanceof PsiArrayType
) {
140 return !settings
.preserveRawArrays() && isRaw(((PsiArrayType
)t
).getComponentType(), settings
, upper
);
147 * convert external raw types to types explicitly parameterized by Bottom
149 public static PsiType
banalize(final PsiType t
) {
150 if (t
instanceof PsiClassType
) {
151 final PsiClassType
.ClassResolveResult result
= resolveType(t
);
152 final PsiClass theClass
= result
.getElement();
154 if (theClass
== null) {
158 final PsiSubstitutor theSubst
= result
.getSubstitutor();
159 final PsiManager theManager
= theClass
.getManager();
161 PsiSubstitutor subst
= PsiSubstitutor
.EMPTY
;
163 for (final PsiTypeParameter theParm
: theSubst
.getSubstitutionMap().keySet()) {
164 final PsiType actualType
= theSubst
.substitute(theParm
);
166 if (actualType
== null /*|| actualType instanceof PsiWildcardType*/) {
167 subst
= subst
.put(theParm
, Bottom
.BOTTOM
);
169 else if (actualType
instanceof PsiWildcardType
) {
170 final PsiWildcardType wctype
= (PsiWildcardType
)actualType
;
171 final PsiType bound
= wctype
.getBound();
174 subst
= subst
.put(theParm
, actualType
);
177 final PsiType banabound
= banalize(bound
);
179 subst
= subst
.put(theParm
, wctype
.isExtends()
180 ? PsiWildcardType
.createExtends(theManager
, banabound
)
181 : PsiWildcardType
.createSuper(theManager
, banabound
));
185 final PsiType banType
= banalize(actualType
);
187 if (banType
== null) {
191 subst
= subst
.put(theParm
, banType
);
195 return JavaPsiFacade
.getInstance(theManager
.getProject()).getElementFactory().createType(theClass
, subst
);
197 else if (t
instanceof PsiArrayType
) {
198 return banalize(((PsiArrayType
)t
).getComponentType()).createArrayType();
204 public static PsiSubstitutor
composeSubstitutors(PsiSubstitutor f
, PsiSubstitutor g
) {
205 if (f
== PsiSubstitutor
.EMPTY
) {
209 PsiSubstitutor subst
= PsiSubstitutor
.EMPTY
;
210 Set
<PsiTypeParameter
> base
= g
.getSubstitutionMap().keySet();
212 for (PsiTypeParameter p
: base
) {
213 PsiType type
= g
.substitute(p
);
214 subst
= subst
.put(p
, type
== null ?
null : f
.substitute(type
));
220 public static boolean bindsTypeParameters(PsiType t
, HashSet
<PsiTypeParameter
> params
) {
221 if (t
instanceof PsiWildcardType
) {
222 final PsiWildcardType wct
= ((PsiWildcardType
)t
);
223 final PsiType bound
= wct
.getBound();
225 return bound
!= null && wct
.isExtends() && bindsTypeParameters(bound
, params
);
228 final PsiClassType
.ClassResolveResult result
= Util
.resolveType(t
);
229 final PsiClass theClass
= result
.getElement();
230 final PsiSubstitutor theSubst
= result
.getSubstitutor();
232 if (theClass
== null) {
236 if (theClass
instanceof PsiTypeParameter
) {
237 return params
== null || params
.contains(theClass
);
239 else if (theClass
.hasTypeParameters()) {
240 for (PsiTypeParameter parameter
: PsiUtil
.typeParametersIterable(theClass
)) {
241 PsiType bound
= theSubst
.substitute(parameter
);
243 if (bound
!= null && bindsTypeParameters(bound
, params
)) {
252 public static PsiType
getType(PsiElement element
) {
253 if (element
instanceof PsiVariable
) {
254 return ((PsiVariable
)element
).getType();
256 else if (element
instanceof PsiExpression
) {
257 return ((PsiExpression
)element
).getType();
259 else if (element
instanceof PsiMethod
) {
260 return ((PsiMethod
)element
).getReturnType();
266 public static PsiType
createParameterizedType(final PsiType t
, final PsiTypeVariableFactory factory
, final PsiElement context
) {
267 return createParameterizedType(t
, factory
, true, context
);
270 public static PsiType
createParameterizedType(final PsiType t
, final PsiTypeVariableFactory factory
) {
271 return createParameterizedType(t
, factory
, true, null);
274 private static PsiType
createParameterizedType(final PsiType t
,
275 final PsiTypeVariableFactory factory
,
277 final PsiElement context
) {
278 if (t
== null || (upper
&& t
.getCanonicalText().equals("java.lang.Object"))) {
279 return factory
.create(context
);
282 if (t
instanceof PsiClassType
) {
283 final PsiClassType
.ClassResolveResult result
= resolveType(t
);
284 final PsiSubstitutor aSubst
= result
.getSubstitutor();
285 final PsiClass aClass
= result
.getElement();
287 PsiSubstitutor theSubst
= PsiSubstitutor
.EMPTY
;
289 final HashSet
<PsiTypeVariable
> cluster
= new HashSet
<PsiTypeVariable
>();
291 for (final PsiTypeParameter parm
: aSubst
.getSubstitutionMap().keySet()) {
292 final PsiType type
= createParameterizedType(aSubst
.substitute(parm
), factory
, false, context
);
294 if (type
instanceof PsiTypeVariable
) {
295 cluster
.add((PsiTypeVariable
)type
);
298 theSubst
= theSubst
.put(parm
, type
);
301 if (cluster
.size() > 1) {
302 factory
.registerCluster(cluster
);
305 return JavaPsiFacade
.getInstance(aClass
.getProject()).getElementFactory().createType(aClass
, theSubst
);
307 else if (t
instanceof PsiArrayType
) {
308 return createParameterizedType(((PsiArrayType
)t
).getComponentType(), factory
, upper
, context
).createArrayType();
314 public static boolean bindsTypeVariables(final PsiType t
) {
319 if (t
instanceof PsiTypeVariable
) {
323 if (t
instanceof PsiArrayType
) {
324 return bindsTypeVariables(((PsiArrayType
)t
).getComponentType());
327 if (t
instanceof PsiWildcardType
) {
328 return bindsTypeVariables(((PsiWildcardType
)t
).getBound());
331 if (t
instanceof PsiIntersectionType
) {
332 final PsiType
[] conjuncts
= ((PsiIntersectionType
)t
).getConjuncts();
333 for (PsiType conjunct
: conjuncts
) {
334 if (bindsTypeVariables(conjunct
)) return true;
339 final PsiClassType
.ClassResolveResult result
= resolveType(t
);
341 if (result
.getElement() != null) {
342 final PsiSubstitutor subst
= result
.getSubstitutor();
344 for (final PsiType psiType
: subst
.getSubstitutionMap().values()) {
345 if (bindsTypeVariables(psiType
)) {
354 public static void changeType(final PsiElement element
, final PsiType type
) {
356 if (element
instanceof PsiTypeCastExpression
) {
357 final PsiTypeCastExpression cast
= ((PsiTypeCastExpression
)element
);
359 cast
.getCastType().replace(JavaPsiFacade
.getInstance(cast
.getProject()).getElementFactory().createTypeElement(type
));
361 else if (element
instanceof PsiVariable
) {
362 final PsiVariable field
= ((PsiVariable
)element
);
364 field
.normalizeDeclaration();
365 field
.getTypeElement().replace(JavaPsiFacade
.getInstance(field
.getProject()).getElementFactory().createTypeElement(type
));
367 else if (element
instanceof PsiMethod
) {
368 final PsiMethod method
= ((PsiMethod
)element
);
370 method
.getReturnTypeElement().replace(JavaPsiFacade
.getInstance(method
.getProject()).getElementFactory().createTypeElement(type
));
372 else if (element
instanceof PsiNewExpression
) {
373 final PsiNewExpression newx
= (PsiNewExpression
)element
;
374 final PsiClassType
.ClassResolveResult result
= Util
.resolveType(type
);
376 if (result
== null) {
380 final PsiSubstitutor subst
= result
.getSubstitutor();
381 final PsiTypeParameter
[] parms
= result
.getElement().getTypeParameters();
383 if (parms
.length
> 0 && subst
.substitute(parms
[0]) != null) {
384 PsiJavaCodeReferenceElement classReference
= newx
.getClassOrAnonymousClassReference();
385 PsiReferenceParameterList list
= classReference
.getParameterList();
391 final PsiElementFactory factory
= JavaPsiFacade
.getInstance(newx
.getProject()).getElementFactory();
393 PsiTypeElement
[] elements
= list
.getTypeParameterElements();
394 for (PsiTypeElement element1
: elements
) {
398 for (PsiTypeParameter parm
: parms
) {
399 PsiType aType
= subst
.substitute(parm
);
401 if (aType
instanceof PsiWildcardType
) {
402 aType
= ((PsiWildcardType
)aType
).getBound();
406 .add(factory
.createTypeElement(aType
== null ? PsiType
.getJavaLangObject(list
.getManager(), list
.getResolveScope()) : aType
));
411 LOG
.error("Unexpected element type " + element
.getClass().getName());
414 catch (IncorrectOperationException e
) {
415 LOG
.error("Incorrect Operation Exception thrown in CastRole.\n");