lambda highlighting: if return statement has problem, try to highlight only corresponding return even if containing inference failed

This commit is contained in:
Anna.Kozlova
2016-10-07 13:55:01 +02:00
parent c0de6f3d36
commit b560ee5910
5 changed files with 68 additions and 69 deletions
@@ -325,77 +325,65 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
myHolder.add(checkFeature(expression, Feature.LAMBDA_EXPRESSIONS));
final PsiElement parent = PsiUtil.skipParenthesizedExprUp(expression.getParent());
if (parent instanceof PsiExpressionStatement) return;
if (!myHolder.hasErrorResults() && !LambdaUtil.isValidLambdaContext(parent)) {
myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression)
.descriptionAndTooltip("Lambda expression not expected here").create());
}
PsiType functionalInterfaceType = null;
if (!myHolder.hasErrorResults()) {
if (LambdaUtil.isValidLambdaContext(parent)) {
final PsiType functionalInterfaceType = expression.getFunctionalInterfaceType();
if (functionalInterfaceType != null) {
final String notFunctionalMessage = LambdaHighlightingUtil.checkInterfaceFunctional(functionalInterfaceType);
if (notFunctionalMessage != null) {
HighlightInfo result =
HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(notFunctionalMessage)
.create();
myHolder.add(result);
}
else {
final PsiCallExpression callExpression = parent instanceof PsiExpressionList && parent.getParent() instanceof PsiCallExpression ?
(PsiCallExpression)parent.getParent() : null;
final JavaResolveResult containingCallResolveResult = callExpression != null ? callExpression.resolveMethodGenerics() : null;
final String errorMessage;
if (containingCallResolveResult instanceof MethodCandidateInfo) {
errorMessage = ((MethodCandidateInfo)containingCallResolveResult).getParentInferenceErrorMessage((PsiExpressionList)parent);
}
else {
errorMessage = null;
}
if (errorMessage != null) {
HighlightInfo result = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR)
.range(expression).descriptionAndTooltip(errorMessage).create();
myHolder.add(result);
}
else {
final Map<PsiElement, String> returnErrors = LambdaUtil
.checkReturnTypeCompatible(expression, LambdaUtil.getFunctionalInterfaceReturnType(functionalInterfaceType));
if (returnErrors != null) {
for (Map.Entry<PsiElement, String> entry : returnErrors.entrySet()) {
myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR)
.range(entry.getKey())
.descriptionAndTooltip(entry.getValue()).create());
}
}
else {
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType);
final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(resolveResult);
if (interfaceMethod != null) {
final PsiParameter[] parameters = interfaceMethod.getParameterList().getParameters();
HighlightInfo result = LambdaHighlightingUtil
.checkParametersCompatible(expression, parameters, LambdaUtil.getSubstitutor(interfaceMethod, resolveResult));
if (result != null) {
myHolder.add(result);
}
else {
checkFunctionalInterfaceTypeAccessible(expression, functionalInterfaceType);
}
}
}
}
}
functionalInterfaceType = expression.getFunctionalInterfaceType();
if (functionalInterfaceType != null) {
final String notFunctionalMessage = LambdaHighlightingUtil.checkInterfaceFunctional(functionalInterfaceType);
if (notFunctionalMessage != null) {
myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression)
.descriptionAndTooltip(notFunctionalMessage).create());
}
else if (LambdaUtil.getFunctionalInterfaceType(expression, true) != null) {
myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip("Cannot infer functional interface type").create());
else {
checkFunctionalInterfaceTypeAccessible(expression, functionalInterfaceType);
}
}
else {
HighlightInfo result = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression)
.descriptionAndTooltip("Lambda expression not expected here").create();
myHolder.add(result);
else if (LambdaUtil.getFunctionalInterfaceType(expression, true) != null) {
myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip("Cannot infer functional interface type").create());
}
if (!myHolder.hasErrorResults()) {
final PsiElement body = expression.getBody();
if (body instanceof PsiCodeBlock) {
myHolder.add(HighlightControlFlowUtil.checkUnreachableStatement((PsiCodeBlock)body));
}
if (!myHolder.hasErrorResults() && functionalInterfaceType != null) {
String parentInferenceErrorMessage = null;
final PsiCallExpression callExpression = parent instanceof PsiExpressionList && parent.getParent() instanceof PsiCallExpression ?
(PsiCallExpression)parent.getParent() : null;
final JavaResolveResult containingCallResolveResult = callExpression != null ? callExpression.resolveMethodGenerics() : null;
if (containingCallResolveResult instanceof MethodCandidateInfo) {
parentInferenceErrorMessage = ((MethodCandidateInfo)containingCallResolveResult).getParentInferenceErrorMessage((PsiExpressionList)parent);
}
final Map<PsiElement, String> returnErrors = LambdaUtil.checkReturnTypeCompatible(expression, LambdaUtil.getFunctionalInterfaceReturnType(functionalInterfaceType));
if (parentInferenceErrorMessage != null && (returnErrors == null || !returnErrors.containsValue(parentInferenceErrorMessage))) {
myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(parentInferenceErrorMessage).create());
}
else if (returnErrors != null) {
for (Map.Entry<PsiElement, String> entry : returnErrors.entrySet()) {
myHolder.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR)
.range(entry.getKey())
.descriptionAndTooltip(entry.getValue()).create());
}
}
}
if (!myHolder.hasErrorResults() && functionalInterfaceType != null) {
final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(functionalInterfaceType);
final PsiMethod interfaceMethod = LambdaUtil.getFunctionalInterfaceMethod(resolveResult);
if (interfaceMethod != null) {
final PsiParameter[] parameters = interfaceMethod.getParameterList().getParameters();
myHolder.add(LambdaHighlightingUtil.checkParametersCompatible(expression, parameters, LambdaUtil.getSubstitutor(interfaceMethod, resolveResult)));
}
}
if (!myHolder.hasErrorResults()) {
final PsiElement body = expression.getBody();
if (body instanceof PsiCodeBlock) {
myHolder.add(HighlightControlFlowUtil.checkUnreachableStatement((PsiCodeBlock)body));
}
}
}
@Override
@@ -33,7 +33,7 @@ class TypeArgsConsistency1 {
I<Integer> i1 = (i, j) -> i + j;
foo((i, j) -> i + j);
I<Integer> i2 =bar((i, j) -> i) ;
I<Integer> i3 = bar(<error descr="Bad return type in lambda expression: String cannot be converted to int">(i, j) -> "" + i + j</error>);
I<Integer> i3 = bar((i, j) -> <error descr="Bad return type in lambda expression: String cannot be converted to int">"" + i + j</error>);
}
}
@@ -66,9 +66,9 @@ class Test2 {
{
bar(x -> x);
bar1(x -> x);
bar2(1, <error descr="Bad return type in lambda expression: List<Integer> cannot be converted to Integer">x -> x</error>);
bar2("", <error descr="Bad return type in lambda expression: List<String> cannot be converted to String">x -> x</error>);
bar3(<error descr="Bad return type in lambda expression: List<String> cannot be converted to String">x -> x</error>, "");
bar2(1, x -> <error descr="Bad return type in lambda expression: List<Integer> cannot be converted to Integer">x</error>);
bar2("", x -> <error descr="Bad return type in lambda expression: List<String> cannot be converted to String">x</error>);
bar3(x -> <error descr="Bad return type in lambda expression: List<String> cannot be converted to String">x</error>, "");
}
}
@@ -1,4 +1,5 @@
import java.util.Collections;
import java.util.List;
import java.util.function.Supplier;
class Test {
@@ -12,4 +13,14 @@ class Test {
}
public static void foo(Supplier<String> consumer) {}
private void foo(List<String> descriptions) {
Collections.sort(descriptions, (o1, o2) -> {
final int elementsDiff = o1.length() - o2.length();
if (elementsDiff == 0) {
return <error descr="Bad return type in lambda expression: boolean cannot be converted to int">o1.equals(o2)</error>;
}
return -elementsDiff;
});
}
}
@@ -13,7 +13,7 @@ class Test {
}
void bar(C c) {
foo(c, <error descr="Bad return type in lambda expression: A cannot be converted to C">x -> x.f()</error>);
foo(c, x -> <error descr="Bad return type in lambda expression: A cannot be converted to C">x.f()</error>);
foo(c, x -> x);
}