| /* |
| * Copyright 2000-2011 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.psi.util; |
| |
| import com.intellij.lang.ASTNode; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.util.Comparing; |
| import com.intellij.openapi.util.Condition; |
| import com.intellij.pom.java.LanguageLevel; |
| import com.intellij.psi.*; |
| import com.intellij.psi.tree.IElementType; |
| import gnu.trove.THashMap; |
| import org.jetbrains.annotations.NonNls; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import java.util.Map; |
| |
| public class PsiTypesUtil { |
| @NonNls private static final Map<String, String> ourUnboxedTypes = new THashMap<String, String>(); |
| @NonNls private static final Map<String, String> ourBoxedTypes = new THashMap<String, String>(); |
| |
| static { |
| ourUnboxedTypes.put(CommonClassNames.JAVA_LANG_BOOLEAN, "boolean"); |
| ourUnboxedTypes.put(CommonClassNames.JAVA_LANG_BYTE, "byte"); |
| ourUnboxedTypes.put(CommonClassNames.JAVA_LANG_SHORT, "short"); |
| ourUnboxedTypes.put(CommonClassNames.JAVA_LANG_INTEGER, "int"); |
| ourUnboxedTypes.put(CommonClassNames.JAVA_LANG_LONG, "long"); |
| ourUnboxedTypes.put(CommonClassNames.JAVA_LANG_FLOAT, "float"); |
| ourUnboxedTypes.put(CommonClassNames.JAVA_LANG_DOUBLE, "double"); |
| ourUnboxedTypes.put(CommonClassNames.JAVA_LANG_CHARACTER, "char"); |
| |
| ourBoxedTypes.put("boolean", CommonClassNames.JAVA_LANG_BOOLEAN); |
| ourBoxedTypes.put("byte", CommonClassNames.JAVA_LANG_BYTE); |
| ourBoxedTypes.put("short", CommonClassNames.JAVA_LANG_SHORT); |
| ourBoxedTypes.put("int", CommonClassNames.JAVA_LANG_INTEGER); |
| ourBoxedTypes.put("long", CommonClassNames.JAVA_LANG_LONG); |
| ourBoxedTypes.put("float", CommonClassNames.JAVA_LANG_FLOAT); |
| ourBoxedTypes.put("double", CommonClassNames.JAVA_LANG_DOUBLE); |
| ourBoxedTypes.put("char", CommonClassNames.JAVA_LANG_CHARACTER); |
| } |
| |
| @NonNls private static final String GET_CLASS_METHOD = "getClass"; |
| |
| private PsiTypesUtil() { } |
| |
| public static String getDefaultValueOfType(PsiType type) { |
| if (type instanceof PsiArrayType) { |
| int count = type.getArrayDimensions() - 1; |
| PsiType componentType = type.getDeepComponentType(); |
| |
| if (componentType instanceof PsiClassType) { |
| final PsiClassType classType = (PsiClassType)componentType; |
| if (classType.resolve() instanceof PsiTypeParameter) { |
| return PsiKeyword.NULL; |
| } |
| } |
| |
| StringBuilder buffer = new StringBuilder(); |
| buffer.append(PsiKeyword.NEW); |
| buffer.append(" "); |
| buffer.append(componentType.getCanonicalText()); |
| buffer.append("[0]"); |
| for (int i = 0; i < count; i++) { |
| buffer.append("[]"); |
| } |
| return buffer.toString(); |
| } |
| else if (type instanceof PsiPrimitiveType) { |
| if (PsiType.BOOLEAN.equals(type)) { |
| return PsiKeyword.FALSE; |
| } |
| else { |
| return "0"; |
| } |
| } |
| else { |
| return PsiKeyword.NULL; |
| } |
| } |
| |
| /** |
| * Returns the unboxed type name or parameter. |
| * @param type boxed java type name |
| * @return unboxed type name if available; same value otherwise |
| */ |
| @Nullable |
| public static String unboxIfPossible(final String type) { |
| if (type == null) return null; |
| final String s = ourUnboxedTypes.get(type); |
| return s == null? type : s; |
| } |
| |
| /** |
| * Returns the boxed type name or parameter. |
| * @param type primitive java type name |
| * @return boxed type name if available; same value otherwise |
| */ |
| @Nullable |
| public static String boxIfPossible(final String type) { |
| if (type == null) return null; |
| final String s = ourBoxedTypes.get(type); |
| return s == null ? type : s; |
| } |
| |
| @Nullable |
| public static PsiClass getPsiClass(final PsiType psiType) { |
| return psiType instanceof PsiClassType? ((PsiClassType)psiType).resolve() : null; |
| } |
| |
| public static PsiClassType getClassType(@NotNull PsiClass psiClass) { |
| return JavaPsiFacade.getElementFactory(psiClass.getProject()).createType(psiClass); |
| } |
| |
| @Nullable |
| public static PsiClassType getLowestUpperBoundClassType(@NotNull final PsiDisjunctionType type) { |
| final PsiType lub = type.getLeastUpperBound(); |
| if (lub instanceof PsiClassType) { |
| return (PsiClassType)lub; |
| } |
| else if (lub instanceof PsiIntersectionType) { |
| for (PsiType subType : ((PsiIntersectionType)lub).getConjuncts()) { |
| if (subType instanceof PsiClassType) { |
| final PsiClass aClass = ((PsiClassType)subType).resolve(); |
| if (aClass != null && !aClass.isInterface()) { |
| return (PsiClassType)subType; |
| } |
| } |
| } |
| } |
| return null; |
| } |
| |
| public static PsiType patchMethodGetClassReturnType(@NotNull PsiExpression call, |
| @NotNull PsiReferenceExpression methodExpression, |
| @NotNull PsiMethod method, |
| @Nullable Condition<IElementType> condition, |
| @NotNull LanguageLevel languageLevel) { |
| //JLS3 15.8.2 |
| if (languageLevel.isAtLeast(LanguageLevel.JDK_1_5) && isGetClass(method)) { |
| PsiExpression qualifier = methodExpression.getQualifierExpression(); |
| PsiType qualifierType = null; |
| final Project project = call.getProject(); |
| if (qualifier != null) { |
| qualifierType = TypeConversionUtil.erasure(qualifier.getType()); |
| } |
| else if (condition != null) { |
| ASTNode parent = call.getNode().getTreeParent(); |
| while (parent != null && condition.value(parent.getElementType())) { |
| parent = parent.getTreeParent(); |
| } |
| if (parent != null) { |
| qualifierType = JavaPsiFacade.getInstance(project).getElementFactory().createType((PsiClass)parent.getPsi()); |
| } |
| } |
| PsiElement parent = call.getParent(); |
| boolean captureTopLevelWildcards = parent instanceof PsiReferenceExpression && parent.getParent() instanceof PsiMethodCallExpression || |
| parent instanceof PsiExpressionList; |
| return createJavaLangClassType(methodExpression, qualifierType, captureTopLevelWildcards); |
| } |
| return null; |
| } |
| |
| public static boolean isGetClass(PsiMethod method) { |
| return GET_CLASS_METHOD.equals(method.getName()) && CommonClassNames.JAVA_LANG_OBJECT.equals(method.getContainingClass().getQualifiedName()); |
| } |
| |
| @Nullable |
| public static PsiType createJavaLangClassType(@NotNull PsiElement context, @Nullable PsiType qualifierType, boolean captureTopLevelWildcards) { |
| if (qualifierType != null) { |
| JavaPsiFacade facade = JavaPsiFacade.getInstance(context.getProject()); |
| PsiClass javaLangClass = facade.findClass(CommonClassNames.JAVA_LANG_CLASS, context.getResolveScope()); |
| if (javaLangClass != null && javaLangClass.getTypeParameters().length == 1) { |
| PsiSubstitutor substitutor = PsiSubstitutor.EMPTY. |
| put(javaLangClass.getTypeParameters()[0], PsiWildcardType.createExtends(context.getManager(), qualifierType)); |
| final PsiClassType classType = facade.getElementFactory().createType(javaLangClass, substitutor, PsiUtil.getLanguageLevel(context)); |
| return captureTopLevelWildcards ? PsiUtil.captureToplevelWildcards(classType, context) : classType; |
| } |
| } |
| return null; |
| } |
| |
| @Nullable |
| public static PsiType getExpectedTypeByParent(PsiExpression methodCall) { |
| final PsiElement parent = PsiUtil.skipParenthesizedExprUp(methodCall.getParent()); |
| if (parent instanceof PsiVariable) { |
| if (PsiUtil.checkSameExpression(methodCall, ((PsiVariable)parent).getInitializer())) { |
| return ((PsiVariable)parent).getType(); |
| } |
| } |
| else if (parent instanceof PsiAssignmentExpression) { |
| if (PsiUtil.checkSameExpression(methodCall, ((PsiAssignmentExpression)parent).getRExpression())) { |
| return ((PsiAssignmentExpression)parent).getLExpression().getType(); |
| } |
| } |
| else if (parent instanceof PsiReturnStatement) { |
| final PsiLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(parent, PsiLambdaExpression.class); |
| if (lambdaExpression != null) { |
| return LambdaUtil.getFunctionalInterfaceReturnType(lambdaExpression.getFunctionalInterfaceType()); |
| } |
| else { |
| PsiMethod method = PsiTreeUtil.getParentOfType(parent, PsiMethod.class); |
| if (method != null) { |
| return method.getReturnType(); |
| } |
| } |
| } |
| else if (PsiUtil.isCondition(methodCall, parent)) { |
| return PsiType.BOOLEAN.getBoxedType(parent); |
| } |
| return null; |
| } |
| |
| public static boolean compareTypes(PsiType leftType, PsiType rightType, boolean ignoreEllipsis) { |
| if (ignoreEllipsis) { |
| if (leftType instanceof PsiEllipsisType) { |
| leftType = ((PsiEllipsisType)leftType).toArrayType(); |
| } |
| if (rightType instanceof PsiEllipsisType) { |
| rightType = ((PsiEllipsisType)rightType).toArrayType(); |
| } |
| } |
| return Comparing.equal(leftType, rightType); |
| } |
| } |