blob: 54149613704b2828d801e52122c1ad74b575a3d3 [file] [log] [blame]
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.refactoring.typeCook;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiUtil;
import com.intellij.refactoring.typeCook.deductive.PsiTypeVariableFactory;
import com.intellij.util.IncorrectOperationException;
import java.util.HashSet;
import java.util.Set;
/**
* Created by IntelliJ IDEA.
* User: db
* Date: 30.07.2003
* Time: 18:57:30
* To change this template use Options | File Templates.
*/
public class Util {
private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.typeCook.Util");
public static PsiType createArrayType(PsiType theType, int level) {
while (level-- > 0) {
theType = theType.createArrayType();
}
return theType;
}
public static PsiClassType.ClassResolveResult resolveType(PsiType type) {
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(type);
final PsiClass aClass = resolveResult.getElement();
if (aClass instanceof PsiAnonymousClass) {
final PsiClassType baseClassType = ((PsiAnonymousClass)aClass).getBaseClassType();
return resolveType(resolveResult.getSubstitutor().substitute(baseClassType));
}
return resolveResult;
}
public static PsiType normalize(PsiType t, boolean objectBottom) {
if (t instanceof PsiArrayType) {
PsiType normType = normalize(((PsiArrayType)t).getComponentType(), objectBottom);
return normType == null ? null : normType.createArrayType();
}
else if (t instanceof PsiClassType) {
PsiClassType.ClassResolveResult result = resolveType(t);
if (result == null) {
return null;
}
PsiClass aclass = result.getElement();
PsiSubstitutor subst = result.getSubstitutor();
PsiManager manager = aclass.getManager();
PsiSubstitutor newbst = PsiSubstitutor.EMPTY;
boolean anyBottom = false;
for (PsiTypeParameter typeParameter : PsiUtil.typeParametersIterable(aclass)) {
PsiType p = subst.substitute(typeParameter);
if (p != null) {
PsiType pp = normalize(p, objectBottom);
if (pp == null) {
return null;
}
if (pp == Bottom.BOTTOM || (objectBottom && pp.getCanonicalText().equals(CommonClassNames.JAVA_LANG_OBJECT))) {
anyBottom = true;
}
newbst = newbst.put(typeParameter, pp);
}
else {
anyBottom = true;
}
}
if (anyBottom || newbst == PsiSubstitutor.EMPTY) {
newbst = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createRawSubstitutor(aclass);
}
return JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createType(aclass, newbst);
}
else {
return t;
}
}
public static boolean isRaw(PsiType t, final Settings settings) {
return isRaw(t, settings, true);
}
private static boolean isRaw(PsiType t, final Settings settings, final boolean upper) {
if (t instanceof PsiClassType) {
final PsiClassType.ClassResolveResult resolveResult = resolveType(t);
if (resolveResult.getElement() == null) {
return false;
}
if (PsiClassType.isRaw(resolveResult)) {
return true;
}
final PsiSubstitutor subst = resolveResult.getSubstitutor();
final PsiClass element = resolveResult.getElement();
final PsiManager manager = element.getManager();
if (settings.cookObjects() && upper &&
t.equals(PsiType.getJavaLangObject(manager, GlobalSearchScope.allScope(manager.getProject())))) {
return true;
}
for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(element)) {
final PsiType actual = subst.substitute(parameter);
if (isRaw(actual, settings, false)) return true;
}
return false;
}
else if (t instanceof PsiArrayType) {
return !settings.preserveRawArrays() && isRaw(((PsiArrayType)t).getComponentType(), settings, upper);
}
return false;
}
/**
* convert external raw types to types explicitly parameterized by Bottom
*/
public static PsiType banalize(final PsiType t) {
if (t instanceof PsiClassType) {
final PsiClassType.ClassResolveResult result = resolveType(t);
final PsiClass theClass = result.getElement();
if (theClass == null) {
return t;
}
final PsiSubstitutor theSubst = result.getSubstitutor();
final PsiManager theManager = theClass.getManager();
PsiSubstitutor subst = PsiSubstitutor.EMPTY;
for (final PsiTypeParameter theParm : theSubst.getSubstitutionMap().keySet()) {
final PsiType actualType = theSubst.substitute(theParm);
if (actualType == null /*|| actualType instanceof PsiWildcardType*/) {
subst = subst.put(theParm, Bottom.BOTTOM);
}
else if (actualType instanceof PsiWildcardType) {
final PsiWildcardType wctype = (PsiWildcardType)actualType;
final PsiType bound = wctype.getBound();
if (bound == null) {
subst = subst.put(theParm, actualType);
}
else {
final PsiType banabound = banalize(bound);
subst = subst.put(theParm, wctype.isExtends()
? PsiWildcardType.createExtends(theManager, banabound)
: PsiWildcardType.createSuper(theManager, banabound));
}
}
else {
final PsiType banType = banalize(actualType);
if (banType == null) {
return t;
}
subst = subst.put(theParm, banType);
}
}
return JavaPsiFacade.getInstance(theManager.getProject()).getElementFactory().createType(theClass, subst);
}
else if (t instanceof PsiArrayType) {
return banalize(((PsiArrayType)t).getComponentType()).createArrayType();
}
return t;
}
public static PsiSubstitutor composeSubstitutors(PsiSubstitutor f, PsiSubstitutor g) {
if (f == PsiSubstitutor.EMPTY) {
return g;
}
PsiSubstitutor subst = PsiSubstitutor.EMPTY;
Set<PsiTypeParameter> base = g.getSubstitutionMap().keySet();
for (PsiTypeParameter p : base) {
PsiType type = g.substitute(p);
subst = subst.put(p, type == null ? null : f.substitute(type));
}
return subst;
}
public static boolean bindsTypeParameters(PsiType t, Set<PsiTypeParameter> params) {
if (t instanceof PsiWildcardType) {
final PsiWildcardType wct = ((PsiWildcardType)t);
final PsiType bound = wct.getBound();
return bound != null && wct.isExtends() && bindsTypeParameters(bound, params);
}
final PsiClassType.ClassResolveResult result = resolveType(t);
final PsiClass theClass = result.getElement();
final PsiSubstitutor theSubst = result.getSubstitutor();
if (theClass == null) {
return false;
}
if (theClass instanceof PsiTypeParameter) {
return params == null || params.contains(theClass);
}
else if (theClass.hasTypeParameters()) {
for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable(theClass)) {
PsiType bound = theSubst.substitute(parameter);
if (bound != null && bindsTypeParameters(bound, params)) {
return true;
}
}
}
return false;
}
public static PsiType getType(PsiElement element) {
if (element instanceof PsiVariable) {
return ((PsiVariable)element).getType();
}
else if (element instanceof PsiExpression) {
return ((PsiExpression)element).getType();
}
else if (element instanceof PsiMethod) {
return ((PsiMethod)element).getReturnType();
}
return null;
}
public static PsiType createParameterizedType(final PsiType t, final PsiTypeVariableFactory factory, final PsiElement context) {
return createParameterizedType(t, factory, true, context);
}
public static PsiType createParameterizedType(final PsiType t, final PsiTypeVariableFactory factory) {
return createParameterizedType(t, factory, true, null);
}
private static PsiType createParameterizedType(final PsiType t,
final PsiTypeVariableFactory factory,
final boolean upper,
final PsiElement context) {
if (t == null || (upper && t.getCanonicalText().equals(CommonClassNames.JAVA_LANG_OBJECT))) {
return factory.create(context);
}
if (t instanceof PsiClassType) {
final PsiClassType.ClassResolveResult result = resolveType(t);
final PsiSubstitutor aSubst = result.getSubstitutor();
final PsiClass aClass = result.getElement();
PsiSubstitutor theSubst = PsiSubstitutor.EMPTY;
final Set<PsiTypeVariable> cluster = new HashSet<PsiTypeVariable>();
for (final PsiTypeParameter parm : aSubst.getSubstitutionMap().keySet()) {
final PsiType type = createParameterizedType(aSubst.substitute(parm), factory, false, context);
if (type instanceof PsiTypeVariable) {
cluster.add((PsiTypeVariable)type);
}
theSubst = theSubst.put(parm, type);
}
if (cluster.size() > 1) {
factory.registerCluster(cluster);
}
return JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory().createType(aClass, theSubst);
}
else if (t instanceof PsiArrayType) {
return createParameterizedType(((PsiArrayType)t).getComponentType(), factory, upper, context).createArrayType();
}
return t;
}
public static boolean bindsTypeVariables(final PsiType t) {
if (t == null) {
return false;
}
if (t instanceof PsiTypeVariable) {
return true;
}
if (t instanceof PsiArrayType) {
return bindsTypeVariables(((PsiArrayType)t).getComponentType());
}
if (t instanceof PsiWildcardType) {
return bindsTypeVariables(((PsiWildcardType)t).getBound());
}
if (t instanceof PsiIntersectionType) {
final PsiType[] conjuncts = ((PsiIntersectionType)t).getConjuncts();
for (PsiType conjunct : conjuncts) {
if (bindsTypeVariables(conjunct)) return true;
}
return false;
}
final PsiClassType.ClassResolveResult result = resolveType(t);
if (result.getElement() != null) {
final PsiSubstitutor subst = result.getSubstitutor();
for (final PsiType psiType : subst.getSubstitutionMap().values()) {
if (bindsTypeVariables(psiType)) {
return true;
}
}
}
return false;
}
public static void changeType(final PsiElement element, final PsiType type) {
try {
if (element instanceof PsiTypeCastExpression) {
final PsiTypeCastExpression cast = ((PsiTypeCastExpression)element);
cast.getCastType().replace(JavaPsiFacade.getInstance(cast.getProject()).getElementFactory().createTypeElement(type));
}
else if (element instanceof PsiVariable) {
final PsiVariable field = ((PsiVariable)element);
field.normalizeDeclaration();
field.getTypeElement().replace(JavaPsiFacade.getInstance(field.getProject()).getElementFactory().createTypeElement(type));
}
else if (element instanceof PsiMethod) {
final PsiMethod method = ((PsiMethod)element);
method.getReturnTypeElement().replace(JavaPsiFacade.getInstance(method.getProject()).getElementFactory().createTypeElement(type));
}
else if (element instanceof PsiNewExpression) {
final PsiNewExpression newx = (PsiNewExpression)element;
final PsiClassType.ClassResolveResult result = resolveType(type);
if (result == null) {
return;
}
final PsiSubstitutor subst = result.getSubstitutor();
final PsiTypeParameter[] parms = result.getElement().getTypeParameters();
if (parms.length > 0 && subst.substitute(parms[0]) != null) {
PsiJavaCodeReferenceElement classReference = newx.getClassOrAnonymousClassReference();
PsiReferenceParameterList list = classReference.getParameterList();
if (list == null) {
return;
}
final PsiElementFactory factory = JavaPsiFacade.getInstance(newx.getProject()).getElementFactory();
PsiTypeElement[] elements = list.getTypeParameterElements();
for (PsiTypeElement element1 : elements) {
element1.delete();
}
for (PsiTypeParameter parm : parms) {
PsiType aType = subst.substitute(parm);
if (aType instanceof PsiWildcardType) {
aType = ((PsiWildcardType)aType).getBound();
}
list
.add(factory.createTypeElement(aType == null ? PsiType.getJavaLangObject(list.getManager(), list.getResolveScope()) : aType));
}
}
}
else {
LOG.error("Unexpected element type " + element.getClass().getName());
}
}
catch (IncorrectOperationException e) {
LOG.error("Incorrect Operation Exception thrown in CastRole.\n");
}
}
}