private PsiType processLocalVariableInitializer( final PsiExpression psiExpression ) { PsiType result = null; if( null != psiExpression && !(psiExpression instanceof PsiArrayInitializerExpression) ) { if( psiExpression instanceof PsiConditionalExpression ) { result = RecursionManager.doPreventingRecursion( psiExpression, true, () -> { final PsiExpression thenExpression = ((PsiConditionalExpression)psiExpression).getThenExpression(); final PsiExpression elseExpression = ((PsiConditionalExpression)psiExpression).getElseExpression(); final PsiType thenType = null != thenExpression ? thenExpression.getType() : null; final PsiType elseType = null != elseExpression ? elseExpression.getType() : null; if( thenType == null ) { return elseType; } if( elseType == null ) { return thenType; } if( TypeConversionUtil.isAssignable( thenType, elseType, false ) ) { return thenType; } if( TypeConversionUtil.isAssignable( elseType, thenType, false ) ) { return elseType; } return thenType; } ); } else { result = RecursionManager.doPreventingRecursion( psiExpression, true, psiExpression::getType ); } if( psiExpression instanceof PsiNewExpression ) { final PsiJavaCodeReferenceElement reference = ((PsiNewExpression)psiExpression).getClassOrAnonymousClassReference(); if( reference != null ) { final PsiReferenceParameterList parameterList = reference.getParameterList(); if( parameterList != null ) { final PsiTypeElement[] elements = parameterList.getTypeParameterElements(); if( elements.length == 1 && elements[0].getType() instanceof PsiDiamondType ) { result = TypeConversionUtil.erasure( result ); } } } } } return result; }
private PsiType processLocalVariableInitializer(final PsiExpression psiExpression) { PsiType result = null; if (null != psiExpression && !(psiExpression instanceof PsiArrayInitializerExpression)) { if (psiExpression instanceof PsiConditionalExpression) { result = RecursionManager.doPreventingRecursion(psiExpression, true, new Computable<PsiType>() { @Override public PsiType compute() { final PsiExpression thenExpression = ((PsiConditionalExpression) psiExpression).getThenExpression(); final PsiExpression elseExpression = ((PsiConditionalExpression) psiExpression).getElseExpression(); final PsiType thenType = null != thenExpression ? thenExpression.getType() : null; final PsiType elseType = null != elseExpression ? elseExpression.getType() : null; if (thenType == null) { return elseType; } if (elseType == null) { return thenType; } if (TypeConversionUtil.isAssignable(thenType, elseType, false)) { return thenType; } if (TypeConversionUtil.isAssignable(elseType, thenType, false)) { return elseType; } return thenType; } }); } else { result = RecursionManager.doPreventingRecursion(psiExpression, true, new Computable<PsiType>() { @Override public PsiType compute() { return psiExpression.getType(); } }); } if (psiExpression instanceof PsiNewExpression) { final PsiJavaCodeReferenceElement reference = ((PsiNewExpression) psiExpression).getClassOrAnonymousClassReference(); if (reference != null) { final PsiReferenceParameterList parameterList = reference.getParameterList(); if (parameterList != null) { final PsiTypeElement[] elements = parameterList.getTypeParameterElements(); if (elements.length == 1 && elements[0].getType() instanceof PsiDiamondType) { result = TypeConversionUtil.erasure(result); } } } } } return result; }
@Nullable public <T extends PsiExpression> PsiType getType(@NotNull T expr, @NotNull Function<T, PsiType> f) { final boolean isOverloadCheck = MethodCandidateInfo.isOverloadCheck() || LambdaUtil.isLambdaParameterCheck(); final boolean polyExpression = PsiPolyExpressionUtil.isPolyExpression(expr); PsiType type = isOverloadCheck && polyExpression ? null : myCalculatedTypes.get(expr); if(type == null) { final RecursionGuard.StackStamp dStackStamp = PsiDiamondType.ourDiamondGuard.markStack(); type = f.fun(expr); if(!dStackStamp.mayCacheNow()) { return type; } //cache standalone expression types as they do not depend on the context if(isOverloadCheck && polyExpression) { return type; } if(type == null) { type = TypeConversionUtil.NULL_TYPE; } myCalculatedTypes.put(expr, type); if(type instanceof PsiClassReferenceType) { // convert reference-based class type to the PsiImmediateClassType, since the reference may become invalid PsiClassType.ClassResolveResult result = ((PsiClassReferenceType) type).resolveGenerics(); PsiClass psiClass = result.getElement(); type = psiClass == null ? type // for type with unresolved reference, leave it in the cache // for clients still might be able to retrieve its getCanonicalText() from the reference text : new PsiImmediateClassType(psiClass, result.getSubstitutor(), ((PsiClassReferenceType) type).getLanguageLevel(), type.getAnnotationProvider()); } } if(!type.isValid()) { if(expr.isValid()) { PsiJavaCodeReferenceElement refInside = type instanceof PsiClassReferenceType ? ((PsiClassReferenceType) type).getReference() : null; @NonNls String typeinfo = type + " (" + type.getClass() + ")" + (refInside == null ? "" : "; ref inside: " + refInside + " (" + refInside.getClass() + ") valid:" + refInside.isValid ()); LOG.error("Type is invalid: " + typeinfo + "; expr: '" + expr + "' (" + expr.getClass() + ") is valid"); } else { LOG.error("Expression: '" + expr + "' is invalid, must not be used for getType()"); } } return type == TypeConversionUtil.NULL_TYPE ? null : type; }