enhanced API for nullness
[fedora-idea.git] / java / java-impl / src / com / intellij / refactoring / typeCook / Util.java
blob0a16f04203da1f953cf5e0432374e7ba92e126be
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.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;
26 import java.util.Set;
28 /**
29 * Created by IntelliJ IDEA.
30 * User: db
31 * Date: 30.07.2003
32 * Time: 18:57:30
33 * To change this template use Options | File Templates.
35 public class Util {
36 private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.typeCook.Util");
38 public static PsiType createArrayType(PsiType theType, int level) {
39 while (level-- > 0) {
40 theType = theType.createArrayType();
43 return theType;
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));
53 return resolveResult;
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);
65 if (result == null) {
66 return null;
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);
78 if (p != null) {
79 PsiType pp = normalize(p, objectBottom);
81 if (pp == null) {
82 return null;
85 if (pp == Bottom.BOTTOM || (objectBottom && pp.getCanonicalText().equals("java.lang.Object"))) {
86 anyBottom = true;
89 newbst = newbst.put(typeParameter, pp);
91 else {
92 anyBottom = true;
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);
102 else {
103 return t;
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) {
116 return false;
119 if (PsiClassType.isRaw(resolveResult)) {
120 return true;
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())))) {
129 return true;
132 for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(element)) {
133 final PsiType actual = subst.substitute(parameter);
134 if (isRaw(actual, settings, false)) return true;
137 return false;
139 else if (t instanceof PsiArrayType) {
140 return !settings.preserveRawArrays() && isRaw(((PsiArrayType)t).getComponentType(), settings, upper);
143 return false;
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) {
155 return t;
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();
173 if (bound == null) {
174 subst = subst.put(theParm, actualType);
176 else {
177 final PsiType banabound = banalize(bound);
179 subst = subst.put(theParm, wctype.isExtends()
180 ? PsiWildcardType.createExtends(theManager, banabound)
181 : PsiWildcardType.createSuper(theManager, banabound));
184 else {
185 final PsiType banType = banalize(actualType);
187 if (banType == null) {
188 return t;
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();
201 return t;
204 public static PsiSubstitutor composeSubstitutors(PsiSubstitutor f, PsiSubstitutor g) {
205 if (f == PsiSubstitutor.EMPTY) {
206 return g;
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));
217 return subst;
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) {
233 return false;
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)) {
244 return true;
249 return false;
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();
263 return null;
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,
276 final boolean upper,
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();
311 return t;
314 public static boolean bindsTypeVariables(final PsiType t) {
315 if (t == null) {
316 return false;
319 if (t instanceof PsiTypeVariable) {
320 return true;
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;
336 return false;
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)) {
346 return true;
351 return false;
354 public static void changeType(final PsiElement element, final PsiType type) {
355 try {
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) {
377 return;
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();
387 if (list == null) {
388 return;
391 final PsiElementFactory factory = JavaPsiFacade.getInstance(newx.getProject()).getElementFactory();
393 PsiTypeElement[] elements = list.getTypeParameterElements();
394 for (PsiTypeElement element1 : elements) {
395 element1.delete();
398 for (PsiTypeParameter parm : parms) {
399 PsiType aType = subst.substitute(parm);
401 if (aType instanceof PsiWildcardType) {
402 aType = ((PsiWildcardType)aType).getBound();
405 list
406 .add(factory.createTypeElement(aType == null ? PsiType.getJavaLangObject(list.getManager(), list.getResolveScope()) : aType));
410 else {
411 LOG.error("Unexpected element type " + element.getClass().getName());
414 catch (IncorrectOperationException e) {
415 LOG.error("Incorrect Operation Exception thrown in CastRole.\n");