inference: stop tree up traversal when lambda expression is currently checked

EA-76546 - assert: InferenceSessionContainer.treeWalkUp
IDEA-150168; IDEA-150166
This commit is contained in:
Anna Kozlova
2016-01-08 20:05:35 +01:00
parent f732fb3742
commit 31c6b67ce6
5 changed files with 53 additions and 38 deletions

View File

@@ -16,7 +16,6 @@
package com.intellij.codeInsight;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.RecursionGuard;
import com.intellij.openapi.util.RecursionManager;
@@ -457,7 +456,7 @@ public class ExceptionUtil {
return Collections.emptyList();
}
final PsiSubstitutor substitutor = getSubstitutor(result, methodCall);
final PsiSubstitutor substitutor = result.getSubstitutor();
if (!isArrayClone(method, methodCall) && methodCall instanceof PsiMethodCallExpression) {
final PsiFile containingFile = (containingMethod == null ? methodCall : containingMethod).getContainingFile();
final MethodResolverProcessor processor = new MethodResolverProcessor((PsiMethodCallExpression)methodCall, containingFile);
@@ -471,7 +470,7 @@ public class ExceptionUtil {
if (element instanceof PsiMethod &&
MethodSignatureUtil.areSignaturesEqual(method, (PsiMethod)element) &&
!MethodSignatureUtil.isSuperMethod((PsiMethod)element, method)) {
return Pair.create((PsiMethod)element, getSubstitutor(info, methodCall));
return Pair.create((PsiMethod)element, info.getSubstitutor());
}
return null;
}
@@ -497,25 +496,6 @@ public class ExceptionUtil {
return getUnhandledExceptions(method, methodCall, topElement, substitutor);
}
private static PsiSubstitutor getSubstitutor(final JavaResolveResult result, PsiCallExpression methodCall) {
final PsiLambdaExpression expression = PsiTreeUtil.getParentOfType(methodCall, PsiLambdaExpression.class);
final PsiSubstitutor substitutor;
if (expression != null) {
final PsiElement parent = methodCall.getParent();
final boolean callInReturnStatement = parent == expression ||
parent instanceof PsiReturnStatement && PsiTreeUtil.getParentOfType(parent, PsiLambdaExpression.class, true, PsiMethod.class) == expression;
substitutor = callInReturnStatement ? ourThrowsGuard.doPreventingRecursion(expression, false, new Computable<PsiSubstitutor>() {
@Override
public PsiSubstitutor compute() {
return result.getSubstitutor();
}
}) : result.getSubstitutor();
} else {
substitutor = result.getSubstitutor();
}
return substitutor == null ? ((MethodCandidateInfo)result).getSiteSubstitutor() : substitutor;
}
public static void retainExceptions(List<PsiClassType> ex, List<PsiClassType> thrownEx) {
final List<PsiClassType> replacement = new ArrayList<PsiClassType>();
for (Iterator<PsiClassType> iterator = ex.iterator(); iterator.hasNext(); ) {

View File

@@ -198,18 +198,32 @@ public class InferenceSessionContainer {
if (parent instanceof PsiCall) {
break;
}
if (parent instanceof PsiCodeBlock && PsiTreeUtil.getParentOfType(parent, PsiLambdaExpression.class) == null) {
break;
}
if (parent instanceof PsiLambdaExpression) {
boolean inReturnExpressions = false;
for (PsiExpression expression : LambdaUtil.getReturnExpressions((PsiLambdaExpression)parent)) {
inReturnExpressions |= PsiTreeUtil.isAncestor(expression, context, false);
}
if (!inReturnExpressions) {
final PsiLambdaExpression lambdaExpression = PsiTreeUtil.getParentOfType(parent, PsiLambdaExpression.class);
if (parent instanceof PsiCodeBlock) {
if (lambdaExpression == null) {
break;
}
else {
boolean inReturnExpressions = false;
for (PsiExpression expression : LambdaUtil.getReturnExpressions(lambdaExpression)) {
inReturnExpressions |= PsiTreeUtil.isAncestor(expression, context, false);
}
if (!inReturnExpressions) {
break;
}
if (LambdaUtil.getFunctionalTypeMap().containsKey(lambdaExpression)) {
break;
}
}
}
if (parent instanceof PsiLambdaExpression && LambdaUtil.getFunctionalTypeMap().containsKey(parent)) {
break;
}
final PsiCall psiCall = PsiTreeUtil.getParentOfType(parent, PsiCall.class);
if (psiCall == null) {
break;

View File

@@ -17,7 +17,6 @@ package com.intellij.psi.impl.source.resolve.graphInference.constraints;
import com.intellij.codeInsight.ExceptionUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Condition;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.resolve.graphInference.FunctionalInterfaceParameterizationUtil;
@@ -118,12 +117,7 @@ public class CheckedExceptionCompatibilityConstraint extends InputOutputConstrai
final List<PsiType> thrownTypes = new ArrayList<PsiType>();
final PsiElement body = myExpression instanceof PsiLambdaExpression ? ((PsiLambdaExpression)myExpression).getBody() : myExpression;
if (body != null) {
final List<PsiClassType> exceptions = ExceptionUtil.ourThrowsGuard.doPreventingRecursion(myExpression, false, new Computable<List<PsiClassType>>() {
@Override
public List<PsiClassType> compute() {
return ExceptionUtil.getUnhandledExceptions(new PsiElement[] {body});
}
});
final List<PsiClassType> exceptions = ExceptionUtil.getUnhandledExceptions(new PsiElement[] {body});
if (exceptions != null) {
thrownTypes.addAll(ContainerUtil.filter(exceptions, new Condition<PsiClassType>() {
@Override

View File

@@ -0,0 +1,23 @@
import java.util.Optional;
class Test {
public static void main(String[] args) {
Optional<Either<IllegalArgumentException, String>> eith =
Optional.of(new Either<IllegalArgumentException, String>());
eith.map(either -> {
String foo = Test.foo(either);
return foo;
}).orElse("Hello");
eith.map(either -> {
return Test.foo(either);
}).orElse("Hello");
eith.map(either -> Test.foo(either)).orElse("Hello");
}
private static <X extends Exception, A> A foo(Either<X, A> either) throws X { return null; }
}
class Either<L, R> { }

View File

@@ -264,6 +264,10 @@ public class NewLambdaHighlightingTest extends LightDaemonAnalyzerTestCase {
doTest();
}
public void testCodeBlockLambdaWithIsValueCompatibleChecks() throws Exception {
doTest();
}
private void doTest() {
doTest(false);
}