2 * Copyright 2000-2014 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.psi.util;
18 import com.intellij.openapi.diagnostic.Logger;
19 import com.intellij.openapi.project.Project;
20 import com.intellij.openapi.roots.ProjectRootModificationTracker;
21 import com.intellij.openapi.util.*;
22 import com.intellij.pom.java.LanguageLevel;
23 import com.intellij.psi.*;
24 import com.intellij.psi.search.GlobalSearchScope;
25 import com.intellij.psi.tree.IElementType;
26 import com.intellij.util.Processor;
27 import com.intellij.util.containers.ContainerUtil;
28 import gnu.trove.THashMap;
29 import gnu.trove.THashSet;
30 import gnu.trove.TObjectIntHashMap;
31 import org.jetbrains.annotations.Contract;
32 import org.jetbrains.annotations.NonNls;
33 import org.jetbrains.annotations.NotNull;
34 import org.jetbrains.annotations.Nullable;
36 import java.util.Collection;
37 import java.util.Iterator;
41 import static com.intellij.psi.CommonClassNames.JAVA_LANG_STRING;
43 public class TypeConversionUtil {
44 private static final Logger LOG = Logger.getInstance("#com.intellij.psi.util.TypeConversionUtil");
46 private static final boolean[][] IS_ASSIGNABLE_BIT_SET = {
47 {true, true, false, true, true, true, true}, // byte
48 {false, true, false, true, true, true, true}, // short
49 {false, false, true, true, true, true, true}, // char
50 {false, false, false, true, true, true, true}, // int
51 {false, false, false, false, true, true, true}, // long
52 {false, false, false, false, false, true, true}, // float
53 {false, false, false, false, false, false, true}, // double
56 private static final TObjectIntHashMap<PsiType> TYPE_TO_RANK_MAP = new TObjectIntHashMap<PsiType>();
58 public static final int BYTE_RANK = 1;
59 public static final int SHORT_RANK = 2;
60 public static final int CHAR_RANK = 3;
61 public static final int INT_RANK = 4;
62 public static final int LONG_RANK = 5;
63 private static final int FLOAT_RANK = 6;
64 private static final int DOUBLE_RANK = 7;
65 private static final int BOOL_RANK = 10;
66 private static final int STRING_RANK = 100;
67 private static final int MAX_NUMERIC_RANK = DOUBLE_RANK;
68 public static final PsiType NULL_TYPE = new PsiEllipsisType(PsiType.NULL){
70 public boolean isValid() {
77 public String getPresentableText() {
81 private static final Key<PsiElement> ORIGINAL_CONTEXT = Key.create("ORIGINAL_CONTEXT");
84 TYPE_TO_RANK_MAP.put(PsiType.BYTE, BYTE_RANK);
85 TYPE_TO_RANK_MAP.put(PsiType.SHORT, SHORT_RANK);
86 TYPE_TO_RANK_MAP.put(PsiType.CHAR, CHAR_RANK);
87 TYPE_TO_RANK_MAP.put(PsiType.INT, INT_RANK);
88 TYPE_TO_RANK_MAP.put(PsiType.LONG, LONG_RANK);
89 TYPE_TO_RANK_MAP.put(PsiType.FLOAT, FLOAT_RANK);
90 TYPE_TO_RANK_MAP.put(PsiType.DOUBLE, DOUBLE_RANK);
91 TYPE_TO_RANK_MAP.put(PsiType.BOOLEAN, BOOL_RANK);
94 private TypeConversionUtil() { }
97 * @return true if fromType can be casted to toType
99 public static boolean areTypesConvertible(@NotNull PsiType fromType, @NotNull PsiType toType) {
100 return areTypesConvertible(fromType, toType, null);
104 * @return true if fromType can be casted to toType
106 public static boolean areTypesConvertible(@NotNull PsiType fromType, @NotNull PsiType toType, @Nullable LanguageLevel languageLevel) {
107 if (fromType == toType) return true;
108 final boolean fromIsPrimitive = isPrimitiveAndNotNull(fromType);
109 final boolean toIsPrimitive = isPrimitiveAndNotNull(toType);
110 if (fromIsPrimitive || toIsPrimitive) {
111 if (isVoidType(fromType) || isVoidType(toType)) return false;
112 final int fromTypeRank = getTypeRank(fromType);
113 final int toTypeRank = getTypeRank(toType);
114 if (!toIsPrimitive) {
115 if (fromTypeRank == toTypeRank) return true;
116 if (toType instanceof PsiIntersectionType) {
117 for (PsiType type : ((PsiIntersectionType)toType).getConjuncts()) {
118 if (!areTypesConvertible(fromType, type)) return false;
122 // JLS 5.5: A value of a primitive type can be cast to a reference type by boxing conversion(see 5.1.7)
123 if (!(toType instanceof PsiClassType)) return false;
124 PsiClass toClass = ((PsiClassType)toType).resolve();
125 if (toClass == null || toClass instanceof PsiTypeParameter) return false;
126 PsiClassType boxedType = ((PsiPrimitiveType)fromType).getBoxedType(toClass.getManager(), toType.getResolveScope());
127 return boxedType != null && areTypesConvertible(boxedType, toType);
129 if (!fromIsPrimitive) {
130 // 5.5. Casting Contexts
131 if ((fromTypeRank == SHORT_RANK || fromTypeRank == BYTE_RANK) && toTypeRank == CHAR_RANK) return false;
133 if (fromType instanceof PsiClassType) {
134 if (languageLevel == null) {
135 languageLevel = ((PsiClassType)fromType).getLanguageLevel();
138 if (languageLevel.isAtLeast(LanguageLevel.JDK_1_7)) {
139 final PsiClassType classType = (PsiClassType)fromType;
140 final PsiClass psiClass = classType.resolve();
141 if (psiClass == null) return false;
142 final PsiClassType boxedType = ((PsiPrimitiveType)toType).getBoxedType(psiClass.getManager(), psiClass.getResolveScope());
143 if (boxedType != null && isNarrowingReferenceConversionAllowed(fromType, boxedType)) {
148 return fromTypeRank == toTypeRank ||
149 fromTypeRank <= MAX_NUMERIC_RANK && toTypeRank <= MAX_NUMERIC_RANK && fromTypeRank < toTypeRank;
151 return fromTypeRank == toTypeRank ||
152 fromTypeRank <= MAX_NUMERIC_RANK && toTypeRank <= MAX_NUMERIC_RANK;
155 //type can be casted via widening reference conversion
156 if (isAssignable(toType, fromType)) return true;
158 if (isNullType(fromType) || isNullType(toType)) return true;
160 // or narrowing reference conversion
161 return isNarrowingReferenceConversionAllowed(fromType, toType);
165 * see JLS 5.1.5, JLS3 5.1.6
167 private static boolean isNarrowingReferenceConversionAllowed(@NotNull PsiType fromType, @NotNull PsiType toType) {
168 if (toType instanceof PsiPrimitiveType || fromType instanceof PsiPrimitiveType) return fromType.equals(toType);
169 //Done with primitives
170 if (toType instanceof PsiDiamondType || fromType instanceof PsiDiamondType) return false;
171 if (toType instanceof PsiArrayType && !(fromType instanceof PsiArrayType)) {
172 if (fromType instanceof PsiClassType) {
173 final PsiClass resolved = ((PsiClassType)fromType).resolve();
174 if (resolved instanceof PsiTypeParameter) {
175 for (final PsiClassType boundType : resolved.getExtendsListTypes()) {
176 if (!isNarrowingReferenceConversionAllowed(boundType, toType)) return false;
181 if (fromType instanceof PsiCapturedWildcardType) {
182 return isNarrowingReferenceConversionAllowed(((PsiCapturedWildcardType)fromType).getUpperBound(), toType);
184 return isAssignable(fromType, toType);
186 if (fromType instanceof PsiArrayType) {
187 if (toType instanceof PsiClassType) {
188 final PsiClass resolved = ((PsiClassType)toType).resolve();
189 if (resolved instanceof PsiTypeParameter) {
190 for (final PsiClassType boundType : resolved.getExtendsListTypes()) {
191 if (!areTypesConvertible(fromType, boundType)) return false;
196 return toType instanceof PsiArrayType
197 && isNarrowingReferenceConversionAllowed(((PsiArrayType)fromType).getComponentType(),
198 ((PsiArrayType)toType).getComponentType());
200 //Done with array types
202 if (fromType instanceof PsiIntersectionType) {
203 final PsiType[] conjuncts = ((PsiIntersectionType)fromType).getConjuncts();
204 for (PsiType conjunct : conjuncts) {
205 if (isNarrowingReferenceConversionAllowed(conjunct, toType)) return true;
209 else if (toType instanceof PsiIntersectionType) {
210 if (fromType instanceof PsiClassType && ((PsiClassType)fromType).getLanguageLevel().isAtLeast(LanguageLevel.JDK_1_8)) {
211 for (PsiType conjunct : ((PsiIntersectionType)toType).getConjuncts()) {
212 if (!isNarrowingReferenceConversionAllowed(fromType, conjunct)) return false;
219 if (fromType instanceof PsiDisjunctionType) {
220 return isNarrowingReferenceConversionAllowed(((PsiDisjunctionType)fromType).getLeastUpperBound(), toType);
222 if (toType instanceof PsiDisjunctionType) {
226 if (fromType instanceof PsiWildcardType) {
227 final PsiWildcardType fromWildcard = (PsiWildcardType)fromType;
228 final PsiType bound = fromWildcard.getBound();
229 if (bound == null) return true;
230 if (fromWildcard.isSuper()) {
231 return isAssignable(toType, bound);
233 return isNarrowingReferenceConversionAllowed(bound, toType);
235 if (toType instanceof PsiWildcardType) {
236 final PsiWildcardType toWildcard = (PsiWildcardType)toType;
237 if (toWildcard.isSuper()) return false;
238 final PsiType bound = toWildcard.getBound();
239 return bound == null || isNarrowingReferenceConversionAllowed(fromType, bound);
242 if (toType instanceof PsiCapturedWildcardType) {
243 return isNarrowingReferenceConversionAllowed(fromType, ((PsiCapturedWildcardType)toType).getUpperBound());
245 if (fromType instanceof PsiCapturedWildcardType) {
246 return isNarrowingReferenceConversionAllowed(((PsiCapturedWildcardType)fromType).getUpperBound(), toType);
249 if (isAssignable(fromType, toType)) return true;
251 if (!(fromType instanceof PsiClassType) || !(toType instanceof PsiClassType)) return false;
252 PsiClassType fromClassType = (PsiClassType)fromType;
253 PsiClassType toClassType = (PsiClassType)toType;
255 PsiClassType.ClassResolveResult fromResult = fromClassType.resolveGenerics();
256 final PsiClass fromClass = fromResult.getElement();
257 if (fromClass == null) return false;
258 if (fromClass instanceof PsiTypeParameter) return isNarrowingReferenceConversionAllowed(obtainSafeSuperType((PsiTypeParameter)fromClass), toType);
260 PsiClassType.ClassResolveResult toResult = toClassType.resolveGenerics();
261 final PsiClass toClass = toResult.getElement();
262 if (toClass == null) return false;
263 if (toClass instanceof PsiTypeParameter) return isNarrowingReferenceConversionAllowed(fromType, obtainSafeSuperType((PsiTypeParameter)toClass));
264 //Done with type parameters
266 PsiManager manager = fromClass.getManager();
267 final LanguageLevel languageLevel = toClassType.getLanguageLevel();
268 if (!fromClass.isInterface()) {
269 if (toClass.isInterface()) {
270 return (!fromClass.hasModifierProperty(PsiModifier.FINAL) || fromClass.isInheritor(toClass, true))&&
271 checkSuperTypesWithDifferentTypeArguments(toResult, fromClass, manager, fromResult.getSubstitutor(), null, languageLevel);
274 if (manager.areElementsEquivalent(fromClass, toClass)) {
275 return areSameParameterTypes(fromClassType, toClassType);
278 if (toClass.isInheritor(fromClass, true)) {
279 return checkSuperTypesWithDifferentTypeArguments(fromResult, toClass, manager, toResult.getSubstitutor(), null, languageLevel);
281 else if (fromClass.isInheritor(toClass, true)) {
282 return checkSuperTypesWithDifferentTypeArguments(toResult, fromClass, manager, fromResult.getSubstitutor(), null, languageLevel);
288 else if (!toClass.isInterface()) {
289 if (!toClass.hasModifierProperty(PsiModifier.FINAL)) {
290 return checkSuperTypesWithDifferentTypeArguments(fromResult, toClass, manager, toResult.getSubstitutor(), null, languageLevel);
293 PsiSubstitutor toSubstitutor = getMaybeSuperClassSubstitutor(fromClass, toClass, toResult.getSubstitutor(), null);
294 return toSubstitutor != null && areSameArgumentTypes(fromClass, fromResult.getSubstitutor(), toSubstitutor);
297 else if (languageLevel.compareTo(LanguageLevel.JDK_1_5) < 0) {
298 //In jls2 check for method in both interfaces with the same signature but different return types.
299 Collection<HierarchicalMethodSignature> fromClassMethodSignatures = fromClass.getVisibleSignatures();
300 Collection<HierarchicalMethodSignature> toClassMethodSignatures = toClass.getVisibleSignatures();
302 for (HierarchicalMethodSignature fromMethodSignature : fromClassMethodSignatures) {
303 for (HierarchicalMethodSignature toMethodSignature : toClassMethodSignatures) {
304 if (fromMethodSignature.equals(toMethodSignature)) {
305 final PsiType fromClassReturnType = fromMethodSignature.getMethod().getReturnType();
306 final PsiType toClassReturnType = toMethodSignature.getMethod().getReturnType();
307 if (fromClassReturnType != null
308 && toClassReturnType != null
309 && !fromClassReturnType.equals(toClassReturnType)) {
318 //In jls3 check for super interface with distinct type arguments
319 PsiClassType.ClassResolveResult baseResult;
321 PsiSubstitutor derivedSubstitutor;
322 if (toClass.isInheritor(fromClass, true)) {
323 baseResult = fromResult;
325 derivedSubstitutor = toResult.getSubstitutor();
328 baseResult = toResult;
330 derivedSubstitutor = fromResult.getSubstitutor();
332 return checkSuperTypesWithDifferentTypeArguments(baseResult, derived, manager, derivedSubstitutor, null, languageLevel);
337 private static PsiClassType obtainSafeSuperType(@NotNull PsiTypeParameter typeParameter) {
338 final PsiClassType superType = typeParameter.getSuperTypes()[0];
339 final PsiClassType.ClassResolveResult result = superType.resolveGenerics();
340 final PsiClass superClass = result.getElement();
341 if (superClass != null) {
342 final PsiSubstitutor substitutor = result.getSubstitutor().put(typeParameter, null);
343 return JavaPsiFacade.getInstance(typeParameter.getProject()).getElementFactory().createType(superClass, substitutor);
348 private static boolean checkSuperTypesWithDifferentTypeArguments(@NotNull PsiClassType.ClassResolveResult baseResult,
349 @NotNull PsiClass derived,
350 @NotNull PsiManager manager,
351 @NotNull PsiSubstitutor derivedSubstitutor,
352 Set<PsiClass> visited,
353 @NotNull LanguageLevel languageLevel) {
354 if (visited != null && visited.contains(derived)) return true;
356 if (languageLevel.compareTo(LanguageLevel.JDK_1_5) < 0) return true;
357 PsiClass base = baseResult.getElement();
358 PsiClass[] supers = derived.getSupers();
359 if (manager.areElementsEquivalent(base, derived)) {
360 derivedSubstitutor = getSuperClassSubstitutor(derived, derived, derivedSubstitutor);
361 return areSameArgumentTypes(derived, baseResult.getSubstitutor(), derivedSubstitutor, 1);
364 PsiSubstitutor baseSubstitutor = getMaybeSuperClassSubstitutor(derived, base, baseResult.getSubstitutor(), null);
365 if (baseSubstitutor != null) {
366 derivedSubstitutor = getSuperClassSubstitutor(derived, derived, derivedSubstitutor);
367 if (!areSameArgumentTypes(derived, baseSubstitutor, derivedSubstitutor)) return false;
371 if (visited == null) visited = new THashSet<PsiClass>();
372 visited.add(derived);
373 for (PsiClass aSuper : supers) {
374 PsiSubstitutor s = getSuperClassSubstitutor(aSuper, derived, derivedSubstitutor);
375 if (!checkSuperTypesWithDifferentTypeArguments(baseResult, aSuper, manager, s, visited, languageLevel)) return false;
381 private static boolean areSameParameterTypes(@NotNull PsiClassType type1, @NotNull PsiClassType type2) {
382 PsiClassType.ClassResolveResult resolveResult1 = type1.resolveGenerics();
383 PsiClassType.ClassResolveResult resolveResult2 = type2.resolveGenerics();
384 final PsiClass aClass = resolveResult1.getElement();
385 final PsiClass bClass = resolveResult2.getElement();
386 return aClass != null &&
388 aClass.getManager().areElementsEquivalent(aClass, bClass) &&
389 areSameArgumentTypes(aClass, resolveResult1.getSubstitutor(), resolveResult2.getSubstitutor(), 1);
392 private static boolean areSameArgumentTypes(@NotNull PsiClass aClass, @NotNull PsiSubstitutor substitutor1, @NotNull PsiSubstitutor substitutor2) {
393 return areSameArgumentTypes(aClass, substitutor1, substitutor2, 0);
396 private static boolean areSameArgumentTypes(@NotNull PsiClass aClass,
397 @NotNull PsiSubstitutor substitutor1,
398 @NotNull PsiSubstitutor substitutor2,
400 for (PsiTypeParameter typeParameter : PsiUtil.typeParametersIterable(aClass)) {
401 PsiType typeArg1 = substitutor1.substitute(typeParameter);
402 PsiType typeArg2 = substitutor2.substitute(typeParameter);
403 if (typeArg1 == null || typeArg2 == null) return true;
404 if (TypesDistinctProver.provablyDistinct(typeArg1, typeArg2, level)) return false;
410 public static boolean isPrimitiveAndNotNull(PsiType type) {
411 if (type instanceof PsiCapturedWildcardType) {
412 return isPrimitiveAndNotNull(((PsiCapturedWildcardType)type).getUpperBound());
414 return type instanceof PsiPrimitiveType && !isNullType(type);
417 public static boolean isEnumType(PsiType type) {
418 if (type instanceof PsiCapturedWildcardType) {
419 return isEnumType(((PsiCapturedWildcardType)type).getUpperBound());
421 if (type instanceof PsiClassType) {
422 final PsiClass psiClass = ((PsiClassType)type).resolve();
423 return psiClass != null && psiClass.isEnum();
428 public static boolean isNullType(PsiType type) {
429 return PsiType.NULL.equals(type);
432 public static boolean isFloatOrDoubleType(PsiType type) {
433 return isFloatType(type) || isDoubleType(type);
435 public static boolean isDoubleType(PsiType type) {
436 if (type instanceof PsiCapturedWildcardType) {
437 return isDoubleType(((PsiCapturedWildcardType)type).getUpperBound());
439 return PsiType.DOUBLE.equals(type) || PsiType.DOUBLE.equals(PsiPrimitiveType.getUnboxedType(type));
442 public static boolean isFloatType(PsiType type) {
443 if (type instanceof PsiCapturedWildcardType) {
444 return isFloatType(((PsiCapturedWildcardType)type).getUpperBound());
446 return PsiType.FLOAT.equals(type) || PsiType.FLOAT.equals(PsiPrimitiveType.getUnboxedType(type));
449 public static boolean isLongType(PsiType type) {
450 if (type instanceof PsiCapturedWildcardType) {
451 return isLongType(((PsiCapturedWildcardType)type).getUpperBound());
453 return PsiType.LONG.equals(type) || PsiType.LONG.equals(PsiPrimitiveType.getUnboxedType(type));
456 public static boolean isVoidType(PsiType type) {
457 return PsiType.VOID.equals(type);
460 public static boolean isBooleanType(@Nullable PsiType type) {
461 if (type instanceof PsiCapturedWildcardType) {
462 return isBooleanType(((PsiCapturedWildcardType)type).getUpperBound());
464 return PsiType.BOOLEAN.equals(type) || PsiType.BOOLEAN.equals(PsiPrimitiveType.getUnboxedType(type));
467 public static boolean isNumericType(int typeRank) {
468 return typeRank <= MAX_NUMERIC_RANK;
470 public static boolean isNumericType(PsiType type) {
471 return type != null && isNumericType(getTypeRank(type));
475 * @return 1..MAX_NUMERIC_TYPE if type is primitive numeric type,
476 * BOOL_TYPE for boolean,
477 * STRING_TYPE for String,
478 * Integer.MAX_VALUE for others
480 public static int getTypeRank(@NotNull PsiType type) {
481 if (type instanceof PsiCapturedWildcardType) {
482 type = ((PsiCapturedWildcardType)type).getUpperBound();
484 PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(type);
485 if (unboxedType != null) {
489 int rank = TYPE_TO_RANK_MAP.get(type);
490 if (rank != 0) return rank;
491 if (type.equalsToText(JAVA_LANG_STRING)) return STRING_RANK;
492 return Integer.MAX_VALUE;
496 * @param tokenType JavaTokenType enumeration
497 * @param strict true if operator result type should be convertible to the left operand
498 * @return true if lOperand operator rOperand expression is syntactically correct
500 public static boolean isBinaryOperatorApplicable(IElementType tokenType,
501 PsiExpression lOperand,
502 PsiExpression rOperand,
504 if (lOperand == null || rOperand == null) return true;
505 final PsiType ltype = lOperand.getType();
506 final PsiType rtype = rOperand.getType();
507 return isBinaryOperatorApplicable(tokenType, ltype, rtype, strict);
510 public static boolean isBinaryOperatorApplicable(final IElementType tokenType, final PsiType ltype, final PsiType rtype, final boolean strict) {
511 if (ltype == null || rtype == null) return true;
512 int resultTypeRank = BOOL_RANK;
513 boolean isApplicable = false;
514 final int ltypeRank = getTypeRank(ltype);
515 final int rtypeRank = getTypeRank(rtype);
517 if (tokenType == JavaTokenType.LT || tokenType == JavaTokenType.LE || tokenType == JavaTokenType.GT || tokenType == JavaTokenType.GE) {
518 if (isPrimitiveAndNotNullOrWrapper(ltype) && isPrimitiveAndNotNullOrWrapper(rtype)) {
519 isApplicable = ltypeRank <= MAX_NUMERIC_RANK && rtypeRank <= MAX_NUMERIC_RANK;
522 else if (tokenType == JavaTokenType.EQEQ || tokenType == JavaTokenType.NE) {
523 if (isPrimitiveAndNotNullOrWrapper(ltype) && isPrimitiveAndNotNullOrWrapper(rtype) &&
524 (isPrimitiveAndNotNull(ltype) || isPrimitiveAndNotNull(rtype))) {
525 isApplicable = ltypeRank <= MAX_NUMERIC_RANK && rtypeRank <= MAX_NUMERIC_RANK
526 || ltypeRank == BOOL_RANK && rtypeRank == BOOL_RANK;
529 if (isPrimitiveAndNotNull(ltype)) {
530 if (rtype instanceof PsiClassType) {
531 final LanguageLevel languageLevel = ((PsiClassType)rtype).getLanguageLevel();
532 if (languageLevel.isAtLeast(LanguageLevel.JDK_1_5) &&
533 !languageLevel.isAtLeast(LanguageLevel.JDK_1_8) &&
534 areTypesConvertible(ltype, rtype)) {
540 if (isPrimitiveAndNotNull(rtype)) {
541 if (ltype instanceof PsiClassType) {
542 final LanguageLevel level = ((PsiClassType)ltype).getLanguageLevel();
543 if (level.isAtLeast(LanguageLevel.JDK_1_7) && !level.isAtLeast(LanguageLevel.JDK_1_8) && areTypesConvertible(rtype, ltype)) {
549 isApplicable = areTypesConvertible(ltype, rtype) || areTypesConvertible(rtype, ltype);
552 else if (tokenType == JavaTokenType.PLUS) {
553 if (ltype.equalsToText(JAVA_LANG_STRING)) {
554 isApplicable = !isVoidType(rtype);
555 resultTypeRank = STRING_RANK;
558 else if (rtype.equalsToText(JAVA_LANG_STRING)) {
559 isApplicable = !isVoidType(ltype);
560 resultTypeRank = STRING_RANK;
568 if (isPrimitiveAndNotNullOrWrapper(ltype) && isPrimitiveAndNotNullOrWrapper(rtype)) {
569 resultTypeRank = Math.max(ltypeRank, rtypeRank);
570 isApplicable = ltypeRank <= MAX_NUMERIC_RANK && rtypeRank <= MAX_NUMERIC_RANK;
573 else if (tokenType == JavaTokenType.ASTERISK || tokenType == JavaTokenType.DIV || tokenType == JavaTokenType.PERC ||
574 tokenType == JavaTokenType.MINUS) {
575 if (isPrimitiveAndNotNullOrWrapper(ltype) && isPrimitiveAndNotNullOrWrapper(rtype)) {
576 resultTypeRank = Math.max(ltypeRank, rtypeRank);
577 isApplicable = ltypeRank <= MAX_NUMERIC_RANK && rtypeRank <= MAX_NUMERIC_RANK;
580 else if (tokenType == JavaTokenType.LTLT || tokenType == JavaTokenType.GTGT || tokenType == JavaTokenType.GTGTGT) {
581 if (isPrimitiveAndNotNullOrWrapper(ltype) && isPrimitiveAndNotNullOrWrapper(rtype)) {
582 isApplicable = ltypeRank <= LONG_RANK && rtypeRank <= LONG_RANK;
583 resultTypeRank = INT_RANK;
586 else if (tokenType == JavaTokenType.AND || tokenType == JavaTokenType.OR || tokenType == JavaTokenType.XOR) {
587 if (isPrimitiveAndNotNullOrWrapper(ltype) && isPrimitiveAndNotNullOrWrapper(rtype)) {
588 isApplicable = ltypeRank <= LONG_RANK && rtypeRank <= LONG_RANK
589 || isBooleanType(ltype) && isBooleanType(rtype);
590 resultTypeRank = ltypeRank <= LONG_RANK ? INT_RANK : BOOL_RANK;
593 else if (tokenType == JavaTokenType.ANDAND || tokenType == JavaTokenType.OROR) {
594 if (isPrimitiveAndNotNullOrWrapper(ltype) && isPrimitiveAndNotNullOrWrapper(rtype)) {
595 isApplicable = isBooleanType(ltype) && isBooleanType(rtype);
598 if (isApplicable && strict) {
599 if (resultTypeRank > MAX_NUMERIC_RANK) {
600 isApplicable = ltypeRank == resultTypeRank || ltype.equalsToText(CommonClassNames.JAVA_LANG_OBJECT);
603 isApplicable = ltypeRank <= MAX_NUMERIC_RANK;
609 public static boolean isPrimitiveAndNotNullOrWrapper(PsiType type) {
610 if (type instanceof PsiCapturedWildcardType) {
611 return isPrimitiveAndNotNullOrWrapper(((PsiCapturedWildcardType)type).getUpperBound());
613 if (type instanceof PsiClassType) {
614 return PsiPrimitiveType.getUnboxedType(type) != null;
617 return isPrimitiveAndNotNull(type);
620 public static boolean isUnaryOperatorApplicable(@NotNull PsiJavaToken token, PsiExpression operand) {
621 if (operand == null) return false;
622 PsiType type = operand.getType();
623 return type != null && isUnaryOperatorApplicable(token, type);
626 public static boolean isUnaryOperatorApplicable(@NotNull PsiJavaToken token, @NotNull PsiType type) {
627 IElementType i = token.getTokenType();
628 int typeRank = getTypeRank(type);
629 if (i == JavaTokenType.MINUSMINUS || i == JavaTokenType.PLUSPLUS) {
630 return typeRank <= MAX_NUMERIC_RANK;
632 if (i == JavaTokenType.MINUS || i == JavaTokenType.PLUS) {
633 return typeRank <= MAX_NUMERIC_RANK;
635 if (i == JavaTokenType.TILDE) {
636 return typeRank <= LONG_RANK;
638 if (i == JavaTokenType.EXCL) {
639 return typeRank == BOOL_RANK;
641 LOG.error("unknown token: " + token);
646 * @return true if expression can be the left part of assignment operator
648 public static boolean isLValue(PsiExpression element) {
649 if (element instanceof PsiReferenceExpression) {
650 final PsiReferenceExpression expression = (PsiReferenceExpression)element;
651 final PsiElement resolved = expression.resolve();
652 return resolved instanceof PsiVariable;
654 if (element instanceof PsiParenthesizedExpression) {
655 return isLValue(((PsiParenthesizedExpression)element).getExpression());
657 if (element instanceof PsiArrayAccessExpression) {
658 final PsiArrayAccessExpression arrayAccessExpression = (PsiArrayAccessExpression)element;
659 final PsiExpression arrayExpression = arrayAccessExpression.getArrayExpression();
660 final PsiType type = arrayExpression.getType();
661 if (type == null || !(type instanceof PsiArrayType)) return false;
662 final PsiExpression indexExpression = arrayAccessExpression.getIndexExpression();
663 if (indexExpression == null) return false;
664 final PsiType indexType = indexExpression.getType();
665 if (indexType == null) return false;
666 if (getTypeRank(indexType) <= INT_RANK) return true;
675 public static boolean areTypesAssignmentCompatible(PsiType lType, PsiExpression rExpr) {
676 if (lType == null || rExpr == null) return true;
677 PsiType rType = rExpr.getType();
678 if (rType == null) return false;
679 if (isAssignable(lType, rType)) return true;
680 if (lType instanceof PsiClassType) {
681 lType = PsiPrimitiveType.getUnboxedType(lType);
682 if (lType == null) return false;
685 final int rTypeRank = getTypeRank(rType);
686 if (lType instanceof PsiPrimitiveType
687 && rType instanceof PsiPrimitiveType
688 && rTypeRank >= BYTE_RANK && rTypeRank <= INT_RANK) {
689 final Object rValue = JavaPsiFacade.getInstance(rExpr.getProject()).getConstantEvaluationHelper().computeConstantExpression(rExpr);
691 if (rValue instanceof Number) {
692 value = ((Number)rValue).longValue();
694 else if (rValue instanceof Character) {
695 value = (Character)rValue;
701 if (PsiType.BYTE.equals(lType)) {
702 return -128 <= value && value <= 127;
704 else if (PsiType.SHORT.equals(lType)) {
705 return -32768 <= value && value <= 32767;
707 else if (PsiType.CHAR.equals(lType)) {
708 return 0 <= value && value <= 0xFFFF;
715 * Checks whether values of one type can be assigned to another
717 * @param left type to assign to
718 * @param right type of value
719 * @return true if value of type <code>right</code> can be assigned to an l-value of
720 * type <code>left</code>
722 public static boolean isAssignable(@NotNull PsiType left, @NotNull PsiType right) {
723 return isAssignable(left, right, true);
726 public static boolean isAssignable(@NotNull PsiType left, @NotNull PsiType right, boolean allowUncheckedConversion) {
727 return isAssignable(left, right, allowUncheckedConversion, true);
730 private static boolean isAssignable(@NotNull PsiType left,
731 @NotNull PsiType right,
732 boolean allowUncheckedConversion,
734 if (left == right || left.equals(right)) return true;
736 if (isNullType(right)) {
737 return !(left instanceof PsiPrimitiveType) || isNullType(left);
740 if (right instanceof PsiMethodReferenceType) {
741 final PsiMethodReferenceExpression methodReferenceExpression = ((PsiMethodReferenceType)right).getExpression();
742 if (left instanceof PsiLambdaExpressionType) {
743 final PsiType rType = methodReferenceExpression.getFunctionalInterfaceType();
744 final PsiType lType = ((PsiLambdaExpressionType)left).getExpression().getFunctionalInterfaceType();
745 return Comparing.equal(rType, lType);
746 } else if (left instanceof PsiMethodReferenceType) {
747 final PsiType rType = methodReferenceExpression.getFunctionalInterfaceType();
748 final PsiType lType = ((PsiMethodReferenceType)left).getExpression().getFunctionalInterfaceType();
749 return Comparing.equal(rType, lType);
751 return !(left instanceof PsiArrayType) && methodReferenceExpression.isAcceptable(left);
753 if (right instanceof PsiLambdaExpressionType) {
754 final PsiLambdaExpression rLambdaExpression = ((PsiLambdaExpressionType)right).getExpression();
755 if (left instanceof PsiLambdaExpressionType) {
756 final PsiLambdaExpression lLambdaExpression = ((PsiLambdaExpressionType)left).getExpression();
757 final PsiType rType = rLambdaExpression.getFunctionalInterfaceType();
758 final PsiType lType = lLambdaExpression.getFunctionalInterfaceType();
759 return Comparing.equal(rType, lType);
761 return !(left instanceof PsiArrayType) && rLambdaExpression.isAcceptable(left);
764 if (left instanceof PsiIntersectionType) {
765 PsiType[] conjuncts = ((PsiIntersectionType)left).getConjuncts();
766 for (PsiType conjunct : conjuncts) {
767 if (!isAssignable(conjunct, right, allowUncheckedConversion, capture)) return false;
771 if (right instanceof PsiIntersectionType) {
772 PsiType[] conjuncts = ((PsiIntersectionType)right).getConjuncts();
773 for (PsiType conjunct : conjuncts) {
774 if (isAssignable(left, conjunct, allowUncheckedConversion, capture)) return true;
779 if (right instanceof PsiCapturedWildcardType) {
780 return isAssignable(left, ((PsiCapturedWildcardType)right).getUpperBound(), allowUncheckedConversion, capture);
783 if (left instanceof PsiCapturedWildcardType) {
784 return left.equals(right) || isAssignable(((PsiCapturedWildcardType)left).getLowerBound(), right, allowUncheckedConversion, capture);
787 if (left instanceof PsiWildcardType) {
788 return isAssignableToWildcard((PsiWildcardType)left, right);
790 if (right instanceof PsiWildcardType) {
791 return isAssignableFromWildcard(left, (PsiWildcardType)right);
793 if (right instanceof PsiArrayType) {
794 if (!(left instanceof PsiArrayType)) {
795 if (left instanceof PsiPrimitiveType || PsiUtil.resolveClassInType(left) == null) return false;
796 PsiClass lClass = PsiUtil.resolveClassInType(left);
797 if (lClass == null) return false;
798 if (lClass.isInterface()) {
799 final String qualifiedName = lClass.getQualifiedName();
800 return "java.io.Serializable".equals(qualifiedName) || "java.lang.Cloneable".equals(qualifiedName);
803 return left.equalsToText(CommonClassNames.JAVA_LANG_OBJECT);
806 PsiType lCompType = ((PsiArrayType)left).getComponentType();
807 PsiType rCompType = ((PsiArrayType)right).getComponentType();
808 if (lCompType instanceof PsiPrimitiveType) {
809 return lCompType.equals(rCompType);
811 return !(rCompType instanceof PsiPrimitiveType) && isAssignable(lCompType, rCompType, allowUncheckedConversion, capture);
814 if (left instanceof PsiDisjunctionType) {
815 for (PsiType type : ((PsiDisjunctionType)left).getDisjunctions()) {
816 if (isAssignable(type, right, allowUncheckedConversion, capture)) return true;
820 if (right instanceof PsiDisjunctionType) {
821 return isAssignable(left, ((PsiDisjunctionType)right).getLeastUpperBound(), allowUncheckedConversion, capture);
824 if (left instanceof PsiArrayType) return false;
825 if (right instanceof PsiPrimitiveType) {
826 if (isVoidType(right)) return false;
827 if (!(left instanceof PsiPrimitiveType)) {
828 return left instanceof PsiClassType && isBoxable((PsiClassType)left, (PsiPrimitiveType)right);
830 int leftTypeIndex = TYPE_TO_RANK_MAP.get(left) - 1;
831 int rightTypeIndex = TYPE_TO_RANK_MAP.get(right) - 1;
832 return leftTypeIndex >= 0 &&
833 rightTypeIndex >= 0 &&
834 rightTypeIndex < IS_ASSIGNABLE_BIT_SET.length &&
835 leftTypeIndex < IS_ASSIGNABLE_BIT_SET.length &&
836 IS_ASSIGNABLE_BIT_SET[rightTypeIndex][leftTypeIndex];
838 if (!(right instanceof PsiClassType)) {
839 return false; // must be TypeCook's PsiTypeVariable
841 if (left instanceof PsiPrimitiveType) {
842 return isUnboxable((PsiPrimitiveType)left, (PsiClassType)right);
844 final PsiClassType.ClassResolveResult leftResult = PsiUtil.resolveGenericsClassInType(left);
845 final PsiClassType.ClassResolveResult rightResult = PsiUtil.resolveGenericsClassInType(right);
846 if (leftResult.getElement() == null || rightResult.getElement() == null) {
847 if (leftResult.getElement() != rightResult.getElement()) return false;
848 // let's suppose 2 unknown classes, which could be the same to be the same
849 String lText = left.getPresentableText();
850 String rText = right.getPresentableText();
851 if (lText.equals(rText)) return true;
852 if (lText.length() > rText.length() && lText.endsWith(rText) &&
853 lText.charAt(lText.length() - rText.length() - 1) == '.') {
856 return rText.length() > lText.length()
857 && rText.endsWith(lText)
858 && rText.charAt(rText.length() - lText.length() - 1) == '.';
860 return isClassAssignable(leftResult, rightResult, allowUncheckedConversion, left.getResolveScope(), capture);
863 private static boolean isAssignableFromWildcard(@NotNull PsiType left, @NotNull PsiWildcardType rightWildcardType) {
864 if (rightWildcardType.isSuper()) {
865 final PsiClass aClass = PsiUtil.resolveClassInType(rightWildcardType.getSuperBound());
866 if (aClass instanceof PsiTypeParameter) {
867 final PsiClassType[] types = aClass.getExtendsListTypes();
868 for (PsiClassType type : types) {
869 if (isAssignable(left, type)) return true;
873 return isAssignable(left, rightWildcardType.getExtendsBound());
876 private static boolean isAssignableToWildcard(@NotNull PsiWildcardType wildcardType, @NotNull PsiType right) {
877 if (wildcardType.isSuper()) {
878 return isAssignable(wildcardType.getSuperBound(), right);
880 return isAssignable(wildcardType.getExtendsBound(), right);
883 private static boolean isUnboxable(@NotNull PsiPrimitiveType left, @NotNull PsiClassType right) {
884 final PsiPrimitiveType rightUnboxedType = PsiPrimitiveType.getUnboxedType(right);
885 return rightUnboxedType != null && isAssignable(left, rightUnboxedType);
888 public static boolean boxingConversionApplicable(final PsiType left, final PsiType right) {
889 if (left instanceof PsiPrimitiveType && !PsiType.NULL.equals(left)) {
890 return right instanceof PsiClassType && isAssignable(left, right);
893 if (left instanceof PsiIntersectionType) {
894 for (PsiType lConjunct : ((PsiIntersectionType)left).getConjuncts()) {
895 if (!boxingConversionApplicable(lConjunct, right)) return false;
900 return left instanceof PsiClassType
901 && right instanceof PsiPrimitiveType
902 && !PsiType.NULL.equals(right)
903 && isAssignable(left, right);
906 private static final Key<CachedValue<Set<String>>> POSSIBLE_BOXED_HOLDER_TYPES = Key.create("Types that may be possibly assigned from primitive ones");
908 private static boolean isBoxable(@NotNull PsiClassType left, @NotNull PsiPrimitiveType right) {
909 if (!left.getLanguageLevel().isAtLeast(LanguageLevel.JDK_1_5)) return false;
910 final PsiClass psiClass = left.resolve();
911 if (psiClass == null) return false;
913 final String qname = psiClass.getQualifiedName();
914 if (qname == null || !(psiClass instanceof PsiTypeParameter || getAllBoxedTypeSupers(psiClass).contains(qname))) {
918 final PsiClassType rightBoxed = right.getBoxedType(psiClass.getManager(), left.getResolveScope());
919 return rightBoxed != null && isAssignable(left, rightBoxed);
923 private static Set<String> getAllBoxedTypeSupers(@NotNull PsiClass psiClass) {
924 PsiManager manager = psiClass.getManager();
925 final Project project = psiClass.getProject();
926 CachedValue<Set<String>> boxedHolderTypes = project.getUserData(POSSIBLE_BOXED_HOLDER_TYPES);
927 if (boxedHolderTypes == null) {
928 project.putUserData(POSSIBLE_BOXED_HOLDER_TYPES, boxedHolderTypes = CachedValuesManager.getManager(manager.getProject()).createCachedValue(new CachedValueProvider<Set<String>>() {
930 public Result<Set<String>> compute() {
931 final JavaPsiFacade facade = JavaPsiFacade.getInstance(project);
932 final Set<String> set = new THashSet<String>();
933 for (final String qname : PsiPrimitiveType.getAllBoxedTypeNames()) {
934 final PsiClass boxedClass = facade.findClass(qname, GlobalSearchScope.allScope(project));
935 InheritanceUtil.processSupers(boxedClass, true, new Processor<PsiClass>() {
937 public boolean process(PsiClass psiClass) {
938 ContainerUtil.addIfNotNull(psiClass.getQualifiedName(), set);
943 return Result.create(set, ProjectRootModificationTracker.getInstance(project));
948 return boxedHolderTypes.getValue();
951 private static boolean isClassAssignable(@NotNull PsiClassType.ClassResolveResult leftResult,
952 @NotNull PsiClassType.ClassResolveResult rightResult,
953 boolean allowUncheckedConversion,
954 GlobalSearchScope resolveScope,
956 final PsiClass leftClass = leftResult.getElement();
957 final PsiClass rightClass = rightResult.getElement();
958 if (leftClass == null || rightClass == null) return false;
960 PsiSubstitutor superSubstitutor = JavaClassSupers.getInstance().getSuperClassSubstitutor(leftClass, rightClass, resolveScope,
961 rightResult.getSubstitutor());
962 return superSubstitutor != null && typeParametersAgree(leftResult, rightResult, allowUncheckedConversion, superSubstitutor, capture);
965 private static boolean typeParametersAgree(@NotNull PsiClassType.ClassResolveResult leftResult,
966 @NotNull PsiClassType.ClassResolveResult rightResult,
967 boolean allowUncheckedConversion, PsiSubstitutor superSubstitutor,
969 PsiSubstitutor rightSubstitutor = rightResult.getSubstitutor();
970 PsiClass leftClass = leftResult.getElement();
971 PsiClass rightClass = rightResult.getElement();
973 Iterator<PsiTypeParameter> li = PsiUtil.typeParametersIterator(leftClass);
975 if (!li.hasNext()) return true;
976 PsiSubstitutor leftSubstitutor = leftResult.getSubstitutor();
978 if (!leftClass.getManager().areElementsEquivalent(leftClass, rightClass)) {
979 rightSubstitutor = superSubstitutor;
980 rightClass = leftClass;
982 else if (!PsiUtil.typeParametersIterator(rightClass).hasNext()) return true;
984 Iterator<PsiTypeParameter> ri = PsiUtil.typeParametersIterator(rightClass);
985 while (li.hasNext()) {
986 if (!ri.hasNext()) return false;
987 PsiTypeParameter lp = li.next();
988 PsiTypeParameter rp = ri.next();
989 final PsiType typeLeft = leftSubstitutor.substitute(lp);
990 if (typeLeft == null) continue;
991 final PsiType typeRight = PsiCapturedWildcardType.isCapture() && capture
992 ? rightSubstitutor.substituteWithBoundsPromotion(rp)
993 : rightSubstitutor.substitute(rp);
994 if (typeRight == null) {
995 // compatibility feature: allow to assign raw types to generic ones
996 return allowUncheckedConversion;
998 if (!typesAgree(typeLeft, typeRight, allowUncheckedConversion)) {
1005 private static final RecursionGuard ourGuard = RecursionManager.createGuard("isAssignable");
1007 public static boolean typesAgree(final @NotNull PsiType typeLeft,
1008 final @NotNull PsiType typeRight,
1009 final boolean allowUncheckedConversion) {
1010 if (typeLeft instanceof PsiWildcardType) {
1011 final PsiWildcardType leftWildcard = (PsiWildcardType)typeLeft;
1012 final PsiType leftBound = leftWildcard.getBound();
1013 if (leftBound == null) return true;
1014 if (leftBound.equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) {
1015 if (!leftWildcard.isSuper()) return true;
1016 if (typeRight.equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) return true;
1019 if (typeRight instanceof PsiWildcardType) {
1020 final PsiWildcardType rightWildcard = (PsiWildcardType)typeRight;
1021 if (leftWildcard.isExtends()) {
1022 return rightWildcard.isExtends() && isAssignable(leftBound, rightWildcard.getBound(), allowUncheckedConversion, false);
1025 if (rightWildcard.isSuper()) {
1026 final Boolean assignable = ourGuard.doPreventingRecursion(rightWildcard, true, new NotNullComputable<Boolean>() {
1029 public Boolean compute() {
1030 return isAssignable(rightWildcard.getBound(), leftBound, allowUncheckedConversion, false);
1033 if (assignable != null && assignable) {
1041 if (leftWildcard.isExtends()) {
1042 return isAssignable(leftBound, typeRight, false, false);
1045 final Boolean assignable = ourGuard.doPreventingRecursion(leftWildcard, true, new NotNullComputable<Boolean>() {
1048 public Boolean compute() {
1049 return isAssignable(typeRight, leftBound, false, false);
1052 return assignable == null || assignable.booleanValue();
1057 return typeLeft.equals(typeRight);
1062 public static PsiSubstitutor getClassSubstitutor(@NotNull PsiClass superClassCandidate,
1063 @NotNull PsiClass derivedClassCandidate,
1064 @NotNull PsiSubstitutor derivedSubstitutor) {
1065 if (superClassCandidate.getManager().areElementsEquivalent(superClassCandidate, derivedClassCandidate)) {
1066 PsiTypeParameter[] baseParams = superClassCandidate.getTypeParameters();
1067 PsiTypeParameter[] derivedParams = derivedClassCandidate.getTypeParameters();
1068 if (baseParams.length > 0 && derivedParams.length == 0) {
1069 return JavaPsiFacade.getInstance(superClassCandidate.getProject()).getElementFactory().createRawSubstitutor(superClassCandidate);
1071 return derivedSubstitutor;
1073 return getMaybeSuperClassSubstitutor(superClassCandidate, derivedClassCandidate, derivedSubstitutor, null);
1076 private static final Set<String> ourReportedSuperClassSubstitutorExceptions = ContainerUtil.newConcurrentSet();
1079 * Calculates substitutor that binds type parameters in <code>superClass</code> with
1080 * values that they have in <code>derivedClass</code>, given that type parameters in
1081 * <code>derivedClass</code> are bound by <code>derivedSubstitutor</code>.
1082 * <code>superClass</code> must be a super class/interface of <code>derivedClass</code> (as in
1083 * <code>InheritanceUtil.isInheritorOrSelf(derivedClass, superClass, true)</code>
1085 * @return substitutor (never returns <code>null</code>)
1086 * @see PsiClass#isInheritor(PsiClass, boolean)
1087 * @see InheritanceUtil#isInheritorOrSelf(PsiClass, PsiClass, boolean)
1090 public static PsiSubstitutor getSuperClassSubstitutor(@NotNull PsiClass superClass,
1091 @NotNull PsiClass derivedClass,
1092 @NotNull PsiSubstitutor derivedSubstitutor) {
1093 if (!superClass.hasTypeParameters() && superClass.getContainingClass() == null) return PsiSubstitutor.EMPTY; //optimization and protection against EJB queer hierarchy
1095 Set<PsiClass> visited = new THashSet<PsiClass>();
1096 PsiSubstitutor substitutor = getMaybeSuperClassSubstitutor(superClass, derivedClass, derivedSubstitutor, visited);
1098 if (substitutor == null) {
1099 if (ourReportedSuperClassSubstitutorExceptions.add(derivedClass.getQualifiedName() + "/" + superClass.getQualifiedName())) {
1100 reportHierarchyInconsistency(superClass, derivedClass, visited);
1102 return PsiSubstitutor.EMPTY;
1107 // the same as getSuperClassSubstitutor() but can return null, which means that classes were not inheritors
1109 public static PsiSubstitutor getMaybeSuperClassSubstitutor(@NotNull PsiClass superClass,
1110 @NotNull PsiClass derivedClass,
1111 @NotNull PsiSubstitutor derivedSubstitutor,
1112 @Nullable Set<PsiClass> visited) {
1113 return JavaClassSupers.getInstance().getSuperClassSubstitutor(superClass, derivedClass, derivedClass.getResolveScope(), derivedSubstitutor);
1116 private static void reportHierarchyInconsistency(@NotNull PsiClass superClass, @NotNull PsiClass derivedClass, @NotNull Set<PsiClass> visited) {
1117 final StringBuilder msg = new StringBuilder("Super: " + classInfo(superClass));
1118 msg.append("visited:\n");
1119 for (PsiClass aClass : visited) {
1120 msg.append(" each: " + classInfo(aClass));
1122 msg.append("isInheritor: " + InheritanceUtil.isInheritorOrSelf(derivedClass, superClass, true) + " " + derivedClass.isInheritor(superClass, true));
1123 msg.append("\nhierarchy:\n");
1124 InheritanceUtil.processSupers(derivedClass, true, new Processor<PsiClass>() {
1126 public boolean process(PsiClass psiClass) {
1127 msg.append("each: " + classInfo(psiClass));
1131 LOG.error(msg.toString());
1135 private static String classInfo(@NotNull PsiClass aClass) {
1136 String s = aClass.getQualifiedName() + "(" + aClass.getClass().getName() + "; " + PsiUtilCore.getVirtualFile(aClass) + ");\n";
1138 for (PsiClassType type : aClass.getExtendsListTypes()) {
1139 s += type + " (" + type.getClass().getName() + "; " + type.resolve() + ") ";
1141 s += "\nimplements: ";
1142 for (PsiClassType type : aClass.getImplementsListTypes()) {
1143 s += type + " (" + type.getClass().getName() + "; " + type.resolve() + ") ";
1149 public static PsiSubstitutor getSuperClassSubstitutor(@NotNull PsiClass superClass, @NotNull PsiClassType classType) {
1150 final PsiClassType.ClassResolveResult classResolveResult = classType.resolveGenerics();
1151 return getSuperClassSubstitutor(superClass, classResolveResult.getElement(), classResolveResult.getSubstitutor());
1158 public static PsiType binaryNumericPromotion(PsiType type1, PsiType type2) {
1159 if (isDoubleType(type1)) return unbox(type1);
1160 if (isDoubleType(type2)) return unbox(type2);
1161 if (isFloatType(type1)) return unbox(type1);
1162 if (isFloatType(type2)) return unbox(type2);
1163 if (isLongType(type1)) return unbox(type1);
1164 if (isLongType(type2)) return unbox(type2);
1170 private static PsiType unbox(@NotNull PsiType type) {
1171 if (type instanceof PsiPrimitiveType) return type;
1172 if (type instanceof PsiClassType) {
1173 type = PsiPrimitiveType.getUnboxedType(type);
1174 LOG.assertTrue(type != null);
1177 LOG.error("Invalid type for unboxing "+type);
1181 private static final Set<String> INTEGER_NUMBER_TYPES = new THashSet<String>(5);
1184 INTEGER_NUMBER_TYPES.add(PsiType.BYTE.getCanonicalText());
1185 INTEGER_NUMBER_TYPES.add(PsiType.CHAR.getCanonicalText());
1186 INTEGER_NUMBER_TYPES.add(PsiType.LONG.getCanonicalText());
1187 INTEGER_NUMBER_TYPES.add(PsiType.INT.getCanonicalText());
1188 INTEGER_NUMBER_TYPES.add(PsiType.SHORT.getCanonicalText());
1191 private static final Set<String> PRIMITIVE_TYPES = new THashSet<String>(9);
1194 PRIMITIVE_TYPES.add(PsiType.VOID.getCanonicalText());
1195 PRIMITIVE_TYPES.add(PsiType.BYTE.getCanonicalText());
1196 PRIMITIVE_TYPES.add(PsiType.CHAR.getCanonicalText());
1197 PRIMITIVE_TYPES.add(PsiType.DOUBLE.getCanonicalText());
1198 PRIMITIVE_TYPES.add(PsiType.FLOAT.getCanonicalText());
1199 PRIMITIVE_TYPES.add(PsiType.LONG.getCanonicalText());
1200 PRIMITIVE_TYPES.add(PsiType.INT.getCanonicalText());
1201 PRIMITIVE_TYPES.add(PsiType.SHORT.getCanonicalText());
1202 PRIMITIVE_TYPES.add(PsiType.BOOLEAN.getCanonicalText());
1205 private static final Set<String> PRIMITIVE_WRAPPER_TYPES = new THashSet<String>(8);
1208 PRIMITIVE_WRAPPER_TYPES.add("java.lang.Byte");
1209 PRIMITIVE_WRAPPER_TYPES.add("java.lang.Character");
1210 PRIMITIVE_WRAPPER_TYPES.add("java.lang.Double");
1211 PRIMITIVE_WRAPPER_TYPES.add("java.lang.Float");
1212 PRIMITIVE_WRAPPER_TYPES.add("java.lang.Long");
1213 PRIMITIVE_WRAPPER_TYPES.add("java.lang.Integer");
1214 PRIMITIVE_WRAPPER_TYPES.add("java.lang.Short");
1215 PRIMITIVE_WRAPPER_TYPES.add("java.lang.Boolean");
1218 public static boolean isIntegerNumber(String typeName) {
1219 return INTEGER_NUMBER_TYPES.contains(typeName);
1222 public static boolean isPrimitive(String typeName) {
1223 return PRIMITIVE_TYPES.contains(typeName);
1226 public static boolean isPrimitiveWrapper(String typeName) {
1227 return PRIMITIVE_WRAPPER_TYPES.contains(typeName);
1229 @Contract("null -> false")
1230 public static boolean isAssignableFromPrimitiveWrapper(final PsiType type) {
1231 if (type == null) return false;
1232 return isPrimitiveWrapper(type) ||
1233 type.equalsToText(CommonClassNames.JAVA_LANG_OBJECT) ||
1234 type.equalsToText(CommonClassNames.JAVA_LANG_NUMBER);
1237 @Contract("null -> false")
1238 public static boolean isPrimitiveWrapper(final PsiType type) {
1239 return type != null && isPrimitiveWrapper(type.getCanonicalText());
1242 @Contract("null -> false")
1243 public static boolean isComposite(final PsiType type) {
1244 return type instanceof PsiDisjunctionType || type instanceof PsiIntersectionType;
1247 public static PsiType typeParameterErasure(@NotNull PsiTypeParameter typeParameter) {
1248 return typeParameterErasure(typeParameter, PsiSubstitutor.EMPTY);
1251 private static PsiType typeParameterErasure(@NotNull PsiTypeParameter typeParameter, @NotNull PsiSubstitutor beforeSubstitutor) {
1252 final PsiClassType[] extendsList = typeParameter.getExtendsList().getReferencedTypes();
1253 if (extendsList.length > 0) {
1254 final PsiClass psiClass = extendsList[0].resolve();
1255 if (psiClass instanceof PsiTypeParameter) {
1256 Set<PsiClass> visited = new THashSet<PsiClass>();
1257 visited.add(psiClass);
1258 final PsiTypeParameter boundTypeParameter = (PsiTypeParameter)psiClass;
1259 if (beforeSubstitutor.getSubstitutionMap().containsKey(boundTypeParameter)) {
1260 return erasure(beforeSubstitutor.substitute(boundTypeParameter));
1262 return typeParameterErasureInner(boundTypeParameter, visited, beforeSubstitutor);
1264 else if (psiClass != null) {
1265 return JavaPsiFacade.getInstance(typeParameter.getProject()).getElementFactory().createType(psiClass);
1268 return PsiType.getJavaLangObject(typeParameter.getManager(), typeParameter.getResolveScope());
1271 private static PsiClassType typeParameterErasureInner(PsiTypeParameter typeParameter,
1272 Set<PsiClass> visited,
1273 PsiSubstitutor beforeSubstitutor) {
1274 final PsiClassType[] extendsList = typeParameter.getExtendsList().getReferencedTypes();
1275 if (extendsList.length > 0) {
1276 final PsiClass psiClass = extendsList[0].resolve();
1277 if (psiClass instanceof PsiTypeParameter) {
1278 if (!visited.contains(psiClass)) {
1279 visited.add(psiClass);
1280 if (beforeSubstitutor.getSubstitutionMap().containsKey(psiClass)) {
1281 return (PsiClassType)erasure(beforeSubstitutor.substitute((PsiTypeParameter)psiClass));
1283 return typeParameterErasureInner((PsiTypeParameter)psiClass, visited, beforeSubstitutor);
1286 else if (psiClass != null) {
1287 return JavaPsiFacade.getInstance(typeParameter.getProject()).getElementFactory().createType(psiClass);
1290 return PsiType.getJavaLangObject(typeParameter.getManager(), typeParameter.getResolveScope());
1293 @Contract("null -> null")
1294 public static PsiType erasure(@Nullable PsiType type) {
1295 return erasure(type, PsiSubstitutor.EMPTY);
1298 @Contract("null, _ -> null")
1299 public static PsiType erasure(@Nullable final PsiType type, @NotNull final PsiSubstitutor beforeSubstitutor) {
1300 if (type == null) return null;
1301 return type.accept(new PsiTypeVisitor<PsiType>() {
1304 public PsiType visitType(PsiType type) {
1309 public PsiType visitClassType(PsiClassType classType) {
1310 final PsiClass aClass = classType.resolve();
1311 if (aClass instanceof PsiTypeParameter && !isFreshVariable((PsiTypeParameter)aClass)) {
1312 return typeParameterErasure((PsiTypeParameter)aClass, beforeSubstitutor);
1314 return classType.rawType();
1318 public PsiType visitWildcardType(PsiWildcardType wildcardType) {
1319 return wildcardType;
1324 public PsiType visitCapturedWildcardType(PsiCapturedWildcardType capturedWildcardType) {
1325 return capturedWildcardType.getUpperBound().accept(this);
1329 public PsiType visitPrimitiveType(PsiPrimitiveType primitiveType) {
1330 return primitiveType;
1334 public PsiType visitEllipsisType(PsiEllipsisType ellipsisType) {
1335 final PsiType componentType = ellipsisType.getComponentType();
1336 final PsiType newComponentType = componentType.accept(this);
1337 if (newComponentType == componentType) return ellipsisType;
1338 return newComponentType != null ? newComponentType.createArrayType() : null;
1342 public PsiType visitArrayType(PsiArrayType arrayType) {
1343 final PsiType componentType = arrayType.getComponentType();
1344 final PsiType newComponentType = componentType.accept(this);
1345 if (newComponentType == componentType) return arrayType;
1346 return newComponentType != null ? newComponentType.createArrayType() : null;
1350 public PsiType visitDisjunctionType(PsiDisjunctionType disjunctionType) {
1351 final PsiClassType lub = PsiTypesUtil.getLowestUpperBoundClassType(disjunctionType);
1352 return lub != null ? erasure(lub, beforeSubstitutor) : disjunctionType;
1357 public static Object computeCastTo(final Object operand, final PsiType castType) {
1358 if (operand == null || castType == null) return null;
1360 if (operand instanceof String && castType.equalsToText(JAVA_LANG_STRING)) {
1363 else if (operand instanceof Boolean && PsiType.BOOLEAN.equals(castType)) {
1367 final PsiType primitiveType = wrapperToPrimitive(operand);
1368 if (primitiveType == null) return null;
1369 // identity cast, including (boolean)boolValue
1370 if (castType.equals(primitiveType)) return operand;
1371 final int rankFrom = getTypeRank(primitiveType);
1372 if (rankFrom > caster.length) return null;
1373 final int rankTo = getTypeRank(castType);
1374 if (rankTo > caster.length) return null;
1376 value = caster[rankFrom - 1][rankTo - 1].cast(operand);
1382 public static PsiType unboxAndBalanceTypes(PsiType type1, PsiType type2) {
1383 if (type1 instanceof PsiClassType) type1 = PsiPrimitiveType.getUnboxedType(type1);
1384 if (type2 instanceof PsiClassType) type2 = PsiPrimitiveType.getUnboxedType(type2);
1386 if (PsiType.DOUBLE.equals(type1) || PsiType.DOUBLE.equals(type2)) return PsiType.DOUBLE;
1387 if (PsiType.FLOAT.equals(type1) || PsiType.FLOAT.equals(type2)) return PsiType.FLOAT;
1388 if (PsiType.LONG.equals(type1) || PsiType.LONG.equals(type2)) return PsiType.LONG;
1392 public static IElementType convertEQtoOperation(IElementType eqOpSign) {
1393 IElementType opSign = null;
1394 if (eqOpSign == JavaTokenType.ANDEQ) {
1395 opSign = JavaTokenType.AND;
1397 else if (eqOpSign == JavaTokenType.ASTERISKEQ) {
1398 opSign = JavaTokenType.ASTERISK;
1400 else if (eqOpSign == JavaTokenType.DIVEQ) {
1401 opSign = JavaTokenType.DIV;
1403 else if (eqOpSign == JavaTokenType.GTGTEQ) {
1404 opSign = JavaTokenType.GTGT;
1406 else if (eqOpSign == JavaTokenType.GTGTGTEQ) {
1407 opSign = JavaTokenType.GTGTGT;
1409 else if (eqOpSign == JavaTokenType.LTLTEQ) {
1410 opSign = JavaTokenType.LTLT;
1412 else if (eqOpSign == JavaTokenType.MINUSEQ) {
1413 opSign = JavaTokenType.MINUS;
1415 else if (eqOpSign == JavaTokenType.OREQ) {
1416 opSign = JavaTokenType.OR;
1418 else if (eqOpSign == JavaTokenType.PERCEQ) {
1419 opSign = JavaTokenType.PERC;
1421 else if (eqOpSign == JavaTokenType.PLUSEQ) {
1422 opSign = JavaTokenType.PLUS;
1424 else if (eqOpSign == JavaTokenType.XOREQ) {
1425 opSign = JavaTokenType.XOR;
1431 public static PsiType calcTypeForBinaryExpression(PsiType lType, PsiType rType, @NotNull IElementType sign, boolean accessLType) {
1432 if (sign == JavaTokenType.PLUS) {
1433 // evaluate right argument first, since '+-/*%' is left associative and left operand tends to be bigger
1434 if (rType == null) return null;
1435 if (rType.equalsToText(JAVA_LANG_STRING)) {
1438 if (!accessLType) return NULL_TYPE;
1439 if (lType == null) return null;
1440 if (lType.equalsToText(JAVA_LANG_STRING)) {
1443 return unboxAndBalanceTypes(lType, rType);
1445 if (sign == JavaTokenType.MINUS || sign == JavaTokenType.ASTERISK || sign == JavaTokenType.DIV || sign == JavaTokenType.PERC) {
1446 if (rType == null) return null;
1447 if (!accessLType) return NULL_TYPE;
1448 if (lType == null) return null;
1449 return unboxAndBalanceTypes(lType, rType);
1451 if (sign == JavaTokenType.LTLT || sign == JavaTokenType.GTGT || sign == JavaTokenType.GTGTGT) {
1452 if (!accessLType) return NULL_TYPE;
1453 if (PsiType.BYTE.equals(lType) || PsiType.CHAR.equals(lType) || PsiType.SHORT.equals(lType)) {
1456 if (lType instanceof PsiClassType) lType = PsiPrimitiveType.getUnboxedType(lType);
1459 if (sign == JavaTokenType.EQEQ ||
1460 sign == JavaTokenType.NE ||
1461 sign == JavaTokenType.LT ||
1462 sign == JavaTokenType.GT ||
1463 sign == JavaTokenType.LE ||
1464 sign == JavaTokenType.GE ||
1465 sign == JavaTokenType.OROR ||
1466 sign == JavaTokenType.ANDAND) {
1467 return PsiType.BOOLEAN;
1469 if (sign == JavaTokenType.OR || sign == JavaTokenType.XOR || sign == JavaTokenType.AND) {
1470 if (rType instanceof PsiClassType) rType = PsiPrimitiveType.getUnboxedType(rType);
1472 if (lType instanceof PsiClassType) lType = PsiPrimitiveType.getUnboxedType(lType);
1474 if (rType == null) return null;
1475 if (PsiType.BOOLEAN.equals(rType)) return PsiType.BOOLEAN;
1476 if (!accessLType) return NULL_TYPE;
1477 if (lType == null) return null;
1478 if (PsiType.BOOLEAN.equals(lType)) return PsiType.BOOLEAN;
1479 if (PsiType.LONG.equals(lType) || PsiType.LONG.equals(rType)) return PsiType.LONG;
1482 LOG.error("Unknown token: "+sign);
1487 * See JLS 3.10.2. Floating-Point Literals
1488 * @return true if floating point literal consists of zeros only
1490 public static boolean isFPZero(@NotNull final String text) {
1491 for (int i = 0; i < text.length(); i++) {
1492 final char c = text.charAt(i);
1493 if (Character.isDigit(c) && c != '0') return false;
1494 final char d = Character.toUpperCase(c);
1495 if (d == 'E' || d == 'P') break;
1500 public static boolean areSameFreshVariables(PsiTypeParameter p1, PsiTypeParameter p2) {
1501 final PsiElement originalContext = p1.getUserData(ORIGINAL_CONTEXT);
1502 return originalContext != null && originalContext == p2.getUserData(ORIGINAL_CONTEXT);
1505 public static boolean isFreshVariable(PsiTypeParameter typeParameter) {
1506 return typeParameter.getUserData(ORIGINAL_CONTEXT) != null;
1509 public static void markAsFreshVariable(PsiTypeParameter parameter, PsiElement context) {
1510 parameter.putUserData(ORIGINAL_CONTEXT, context);
1513 private interface Caster {
1515 Object cast(@NotNull Object operand);
1518 private static final Caster[][] caster = {
1523 public Object cast(@NotNull Object operand) {
1530 public Object cast(@NotNull Object operand) {
1531 return (short)((Number)operand).intValue();
1537 public Object cast(@NotNull Object operand) {
1538 return (char)((Number)operand).intValue();
1544 public Object cast(@NotNull Object operand) {
1545 return ((Number)operand).intValue();
1551 public Object cast(@NotNull Object operand) {
1552 return (long)((Number)operand).intValue();
1558 public Object cast(@NotNull Object operand) {
1559 return (float)((Number)operand).intValue();
1565 public Object cast(@NotNull Object operand) {
1566 return (double)((Number)operand).intValue();
1575 public Object cast(@NotNull Object operand) {
1576 return (byte)((Short)operand).shortValue();
1582 public Object cast(@NotNull Object operand) {
1589 public Object cast(@NotNull Object operand) {
1590 return (char)((Short)operand).shortValue();
1596 public Object cast(@NotNull Object operand) {
1597 return (int)(Short)operand;
1603 public Object cast(@NotNull Object operand) {
1604 return (long)(Short)operand;
1610 public Object cast(@NotNull Object operand) {
1611 return (float)(Short)operand;
1617 public Object cast(@NotNull Object operand) {
1618 return (double)(Short)operand;
1627 public Object cast(@NotNull Object operand) {
1628 return (byte)((Character)operand).charValue();
1634 public Object cast(@NotNull Object operand) {
1635 return (short)((Character)operand).charValue();
1641 public Object cast(@NotNull Object operand) {
1648 public Object cast(@NotNull Object operand) {
1649 return (int)(Character)operand;
1655 public Object cast(@NotNull Object operand) {
1656 return (long)(Character)operand;
1662 public Object cast(@NotNull Object operand) {
1663 return (float)(Character)operand;
1669 public Object cast(@NotNull Object operand) {
1670 return (double)(Character)operand;
1679 public Object cast(@NotNull Object operand) {
1680 return (byte)((Integer)operand).intValue();
1686 public Object cast(@NotNull Object operand) {
1687 return (short)((Integer)operand).intValue();
1693 public Object cast(@NotNull Object operand) {
1694 return (char)((Integer)operand).intValue();
1700 public Object cast(@NotNull Object operand) {
1707 public Object cast(@NotNull Object operand) {
1708 return (long)(Integer)operand;
1714 public Object cast(@NotNull Object operand) {
1715 return (float)(Integer)operand;
1721 public Object cast(@NotNull Object operand) {
1722 return (double)(Integer)operand;
1731 public Object cast(@NotNull Object operand) {
1732 return (byte)((Long)operand).longValue();
1738 public Object cast(@NotNull Object operand) {
1739 return (short)((Long)operand).longValue();
1745 public Object cast(@NotNull Object operand) {
1746 return (char)((Long)operand).longValue();
1752 public Object cast(@NotNull Object operand) {
1753 return (int)((Long)operand).longValue();
1759 public Object cast(@NotNull Object operand) {
1766 public Object cast(@NotNull Object operand) {
1767 return (float)(Long)operand;
1773 public Object cast(@NotNull Object operand) {
1774 return (double)(Long)operand;
1783 public Object cast(@NotNull Object operand) {
1784 return (byte)((Float)operand).floatValue();
1790 public Object cast(@NotNull Object operand) {
1791 return (short)((Float)operand).floatValue();
1797 public Object cast(@NotNull Object operand) {
1798 return (char)((Float)operand).floatValue();
1804 public Object cast(@NotNull Object operand) {
1805 return (int)((Float)operand).floatValue();
1811 public Object cast(@NotNull Object operand) {
1812 return (long)((Float)operand).floatValue();
1818 public Object cast(@NotNull Object operand) {
1825 public Object cast(@NotNull Object operand) {
1826 return (double)(Float)operand;
1835 public Object cast(@NotNull Object operand) {
1836 return (byte)((Double)operand).doubleValue();
1842 public Object cast(@NotNull Object operand) {
1843 return (short)((Double)operand).doubleValue();
1849 public Object cast(@NotNull Object operand) {
1850 return (char)((Double)operand).doubleValue();
1856 public Object cast(@NotNull Object operand) {
1857 return (int)((Double)operand).doubleValue();
1863 public Object cast(@NotNull Object operand) {
1864 return (long)((Double)operand).doubleValue();
1870 public Object cast(@NotNull Object operand) {
1871 return new Float((Double)operand);
1877 public Object cast(@NotNull Object operand) {
1884 private static final Map<Class, PsiType> WRAPPER_TO_PRIMITIVE = new THashMap<Class, PsiType>(8);
1886 WRAPPER_TO_PRIMITIVE.put(Boolean.class, PsiType.BOOLEAN);
1887 WRAPPER_TO_PRIMITIVE.put(Byte.class, PsiType.BYTE);
1888 WRAPPER_TO_PRIMITIVE.put(Character.class, PsiType.CHAR);
1889 WRAPPER_TO_PRIMITIVE.put(Short.class, PsiType.SHORT);
1890 WRAPPER_TO_PRIMITIVE.put(Integer.class, PsiType.INT);
1891 WRAPPER_TO_PRIMITIVE.put(Long.class, PsiType.LONG);
1892 WRAPPER_TO_PRIMITIVE.put(Float.class, PsiType.FLOAT);
1893 WRAPPER_TO_PRIMITIVE.put(Double.class, PsiType.DOUBLE);
1896 private static PsiType wrapperToPrimitive(@NotNull Object o) {
1897 return WRAPPER_TO_PRIMITIVE.get(o.getClass());