@Override public void visitConditionalExpression(PsiConditionalExpression expression) { super.visitConditionalExpression(expression); if (myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_8) && PsiPolyExpressionUtil.isPolyExpression(expression)) { final PsiExpression thenExpression = expression.getThenExpression(); final PsiExpression elseExpression = expression.getElseExpression(); if (thenExpression != null && elseExpression != null) { final PsiType conditionalType = expression.getType(); if (conditionalType != null) { final PsiExpression[] sides = {thenExpression, elseExpression}; for (PsiExpression side : sides) { final PsiType sideType = side.getType(); if (sideType != null && !TypeConversionUtil.isAssignable(conditionalType, sideType)) { myHolder.add(HighlightUtil.checkAssignability(conditionalType, sideType, side, side)); } } } } } }
private void processMemberType(final PsiElement element, final Set<PsiTypeParameter> typeParameters, final PsiClass psiClass, final PsiSubstitutor substitutor, final Map<PsiElement, Pair<PsiReference[], PsiType>> roots) { final PsiType elementType = TypeMigrationLabeler.getElementType(element); if(elementType != null && PsiPolyExpressionUtil.mentionsTypeParameters(elementType, typeParameters)) { final PsiType memberType = substitutor.substitute(elementType); prepareMethodsChangeSignature(psiClass, element, memberType); final List<PsiReference> refs = TypeMigrationLabeler.filterReferences(psiClass, ReferencesSearch.search(element, psiClass.getUseScope())); roots.put(element, Pair.create(myLabeler.markRootUsages(element, memberType, refs.toArray(PsiReference.EMPTY_ARRAY)), memberType)); } }
public void testPolyConditionExpression() throws Exception { myFixture.configureByText("Foo.java", "import java.util.*;" + "class Foo {" + " String foo(int i) {" + " return i == 0 <caret>? bar() : bar();" + " }" + " String bar() {return null;}" + "}"); final PsiElement elementAtCaret = myFixture.getFile().findElementAt(myFixture.getCaretOffset()); assertNotNull(elementAtCaret); final PsiExpression psiExpression = PsiTreeUtil.getParentOfType(elementAtCaret, PsiExpression.class); assertInstanceOf(psiExpression, PsiConditionalExpression.class); assertFalse(PsiPolyExpressionUtil.hasStandaloneForm(psiExpression)); assertTrue(PsiPolyExpressionUtil.isPolyExpression(psiExpression)); }
public void testMethodCallInsideArrayCreation() throws Exception { myFixture.configureByText("Foo.java", "import java.util.*;" + "class Foo {" + " <T> T bar() {return null;}" + " void foo() {" + " String[] a = new String[] {ba<caret>r()};" + " }" + "}"); final PsiElement elementAtCaret = myFixture.getFile().findElementAt(myFixture.getCaretOffset()); assertNotNull(elementAtCaret); final PsiExpression psiExpression = PsiTreeUtil.getParentOfType(elementAtCaret, PsiMethodCallExpression.class); assertInstanceOf(psiExpression, PsiMethodCallExpression.class); assertTrue(PsiPolyExpressionUtil.isPolyExpression(psiExpression)); }
public void testConditional() throws Exception { myFixture.configureByText("Foo.java", "import java.util.function.Supplier;" + "class Foo {" + " private static <R> void map(Supplier<R> fn) {}\n" + " public static void main(String[] args) {\n" + " Runnable r = null;\n" + " map(() -> (true <caret>? r : r));\n" + " }" + "}"); final PsiElement elementAtCaret = myFixture.getFile().findElementAt(myFixture.getCaretOffset()); assertNotNull(elementAtCaret); final PsiExpression psiExpression = PsiTreeUtil.getParentOfType(elementAtCaret, PsiExpression.class); assertInstanceOf(psiExpression, PsiConditionalExpression.class); assertTrue(PsiPolyExpressionUtil.isPolyExpression(psiExpression)); }
public void testConditionalInAssignment() throws Exception { myFixture.configureByText("Foo.java", "class Foo {" + " public static void main(String[] args) {\n" + " Object obj = new Object();\n" + " String str = \"\";\n" + " str += args.length == 0 <caret>? obj : args[0];\n" + " }" + "}"); final PsiElement elementAtCaret = myFixture.getFile().findElementAt(myFixture.getCaretOffset()); assertNotNull(elementAtCaret); final PsiExpression psiExpression = PsiTreeUtil.getParentOfType(elementAtCaret, PsiExpression.class); assertInstanceOf(psiExpression, PsiConditionalExpression.class); assertFalse(PsiPolyExpressionUtil.isPolyExpression(psiExpression)); }
private static boolean isAssignable(CallArgumentInfo callArgumentInfo, PsiSubstitutor substitutor) { PsiType substitutedType = substitutor.substitute(callArgumentInfo.getParameter().getType()); if(PsiPolyExpressionUtil.isPolyExpression(callArgumentInfo.getArgument())) { return true; } PsiType type = callArgumentInfo.getArgument().getType(); if(type == null) { return false; } return isAssignableTo(type, substitutedType); }
@Override public void visitConditionalExpression(PsiConditionalExpression expression) { super.visitConditionalExpression(expression); if(myLanguageLevel.isAtLeast(LanguageLevel.JDK_1_8) && PsiPolyExpressionUtil.isPolyExpression(expression)) { final PsiExpression thenExpression = expression.getThenExpression(); final PsiExpression elseExpression = expression.getElseExpression(); if(thenExpression != null && elseExpression != null) { final PsiType conditionalType = expression.getType(); if(conditionalType != null) { final PsiExpression[] sides = { thenExpression, elseExpression }; for(PsiExpression side : sides) { final PsiType sideType = side.getType(); if(sideType != null && !TypeConversionUtil.isAssignable(conditionalType, sideType)) { myHolder.add(HighlightUtil.checkAssignability(conditionalType, sideType, side, side)); } } } } } }
/** * JLS 15.25 */ @Override public PsiType getType() { PsiExpression expr1 = getThenExpression(); PsiExpression expr2 = getElseExpression(); PsiType type1 = expr1 == null ? null : expr1.getType(); PsiType type2 = expr2 == null ? null : expr2.getType(); if (type1 == null) return type2; if (type2 == null) return type1; if (type1.equals(type2)) return type1; final int typeRank1 = TypeConversionUtil.getTypeRank(type1); final int typeRank2 = TypeConversionUtil.getTypeRank(type2); // bug in JLS3, see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6888770 if (type1 instanceof PsiClassType && type2.equals(PsiPrimitiveType.getUnboxedType(type1))) return type2; if (type2 instanceof PsiClassType && type1.equals(PsiPrimitiveType.getUnboxedType(type2))) return type1; if (TypeConversionUtil.isNumericType(typeRank1) && TypeConversionUtil.isNumericType(typeRank2)){ if (typeRank1 == TypeConversionUtil.BYTE_RANK && typeRank2 == TypeConversionUtil.SHORT_RANK) { return type2 instanceof PsiPrimitiveType ? type2 : PsiPrimitiveType.getUnboxedType(type2); } if (typeRank1 == TypeConversionUtil.SHORT_RANK && typeRank2 == TypeConversionUtil.BYTE_RANK) { return type1 instanceof PsiPrimitiveType ? type1 : PsiPrimitiveType.getUnboxedType(type1); } if (typeRank2 == TypeConversionUtil.INT_RANK && (typeRank1 == TypeConversionUtil.BYTE_RANK || typeRank1 == TypeConversionUtil.SHORT_RANK || typeRank1 == TypeConversionUtil.CHAR_RANK)){ if (TypeConversionUtil.areTypesAssignmentCompatible(type1, expr2)) return type1; } if (typeRank1 == TypeConversionUtil.INT_RANK && (typeRank2 == TypeConversionUtil.BYTE_RANK || typeRank2 == TypeConversionUtil.SHORT_RANK || typeRank2 == TypeConversionUtil.CHAR_RANK)){ if (TypeConversionUtil.areTypesAssignmentCompatible(type2, expr1)) return type2; } return TypeConversionUtil.binaryNumericPromotion(type1, type2); } if (TypeConversionUtil.isNullType(type1) && !(type2 instanceof PsiPrimitiveType)) return type2; if (TypeConversionUtil.isNullType(type2) && !(type1 instanceof PsiPrimitiveType)) return type1; if (PsiUtil.isLanguageLevel8OrHigher(this) && PsiPolyExpressionUtil.isPolyExpression(this) && !MethodCandidateInfo.ourOverloadGuard.currentStack().contains(PsiUtil.skipParenthesizedExprUp(this.getParent()))) { //15.25.3 Reference Conditional Expressions // The type of a poly reference conditional expression is the same as its target type. return InferenceSession.getTargetType(this); } if (TypeConversionUtil.isAssignable(type1, type2, false)) return type1; if (TypeConversionUtil.isAssignable(type2, type1, false)) return type2; if (!PsiUtil.isLanguageLevel5OrHigher(this)) { return null; } if (TypeConversionUtil.isPrimitiveAndNotNull(type1)) { type1 = ((PsiPrimitiveType)type1).getBoxedType(this); if (type1 == null) return null; } if (TypeConversionUtil.isPrimitiveAndNotNull(type2)) { type2 = ((PsiPrimitiveType)type2).getBoxedType(this); if (type2 == null) return null; } if (type1 instanceof PsiLambdaParameterType || type2 instanceof PsiLambdaParameterType) return null; final PsiType leastUpperBound = GenericsUtil.getLeastUpperBound(type1, type2, getManager()); return leastUpperBound != null ? PsiUtil.captureToplevelWildcards(leastUpperBound, this) : null; }
public void testPrefixExpression() throws Exception { final PsiExpression psiExpression = findExpression(" int j = i<caret>++;"); assertInstanceOf(psiExpression, PsiPostfixExpression.class); assertTrue(PsiPolyExpressionUtil.hasStandaloneForm(psiExpression)); assertFalse(PsiPolyExpressionUtil.isPolyExpression(psiExpression)); }
public void testNumericConditionExpression() throws Exception { final PsiExpression psiExpression = findExpression(" int j = i == 0 <caret>? i + 1 : i - 1;"); assertInstanceOf(psiExpression, PsiConditionalExpression.class); assertFalse(PsiPolyExpressionUtil.hasStandaloneForm(psiExpression)); assertFalse(PsiPolyExpressionUtil.isPolyExpression(psiExpression)); }
public void testNewExpressionDiamond() throws Exception { final PsiExpression psiExpression = findExpression(" List<String> l = new Arr<caret>ayList<>();"); assertInstanceOf(psiExpression, PsiNewExpression.class); assertFalse(PsiPolyExpressionUtil.hasStandaloneForm(psiExpression)); assertTrue(PsiPolyExpressionUtil.isPolyExpression(psiExpression)); }
public void testNewExpression() throws Exception { final PsiExpression psiExpression = findExpression(" List<String> l = new Arr<caret>ayList<String>();"); assertInstanceOf(psiExpression, PsiNewExpression.class); assertFalse(PsiPolyExpressionUtil.hasStandaloneForm(psiExpression)); assertFalse(PsiPolyExpressionUtil.isPolyExpression(psiExpression)); }
private static boolean isBoxingUsed(PsiType parameterType, @Nullable PsiType argType, PsiExpression arg) { ProgressManager.checkCanceled(); final boolean isExpressionTypePrimitive = argType != null ? argType instanceof PsiPrimitiveType : PsiPolyExpressionUtil.isExpressionOfPrimitiveType(arg); return parameterType instanceof PsiPrimitiveType ^ isExpressionTypePrimitive; }
@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; }