if client iterates through candidates of call resolve results and start inference for one of them, then cached top level session should be rejected if it corresponds to another candidate

This commit is contained in:
Anna.Kozlova
2016-04-06 12:51:57 +02:00
parent 7b7e10ab0c
commit c35fa1891b
4 changed files with 62 additions and 1 deletions
@@ -371,6 +371,9 @@ public class MethodCandidateInfo extends CandidateInfo{
}
}
/**
* If iterated through all candidates, should be called under {@link #ourOverloadGuard} guard so results won't be cached on the top level call
*/
@NotNull
public PsiSubstitutor inferTypeArguments(@NotNull final ParameterTypeInferencePolicy policy,
@NotNull final PsiExpression[] arguments,
@@ -79,7 +79,7 @@ public class InferenceSessionContainer {
});
if (topLevelCall != null) {
final InferenceSession session;
InferenceSession session;
if (MethodCandidateInfo.isOverloadCheck() || !PsiDiamondType.ourDiamondGuard.currentStack().isEmpty() || LambdaUtil.isLambdaParameterCheck()) {
session = startTopLevelInference(topLevelCall);
}
@@ -91,6 +91,22 @@ public class InferenceSessionContainer {
return new Result<InferenceSession>(startTopLevelInference(topLevelCall), PsiModificationTracker.MODIFICATION_COUNT);
}
});
if (session != null) {
//reject cached top level session if it was based on wrong candidate: check nested session if candidate (it's type parameters) are the same
//such situations are avoided when overload resolution is performed (MethodCandidateInfo.isOverloadCheck above)
//but situations when client code iterates through PsiResolveHelper.getReferencedMethodCandidates or similar are impossible to guess
final Map<PsiElement, InferenceSession> sessions = session.getInferenceSessionContainer().myNestedSessions;
final InferenceSession childSession = sessions.get(parent);
if (childSession != null) {
for (PsiTypeParameter parameter : typeParameters) {
if (!childSession.getInferenceSubstitution().getSubstitutionMap().containsKey(parameter)) {
session = startTopLevelInference(topLevelCall);
break;
}
}
}
}
}
if (session != null) {
@@ -0,0 +1,22 @@
import java.util.function.Function;
import java.util.*;
class Test {
void m(Set<String> i) {
final List<String> getters = new ArrayList<String>(ma<caret>p(i, new Function<String, String>() {
@Override
public String apply(String propertyName) {
return propertyName;
}
}));
}
public static <T,V> List<V> map(Iterable<? extends T> iterable, Function<T, V> mapping) {
return null;
}
public static <T,V> List<V> map(Collection<? extends T> iterable, Function<T, V> mapping) {
return null;
}
}
@@ -20,6 +20,8 @@ import com.intellij.codeInsight.ExpectedTypesProvider;
import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.psi.*;
import com.intellij.psi.infos.CandidateInfo;
import com.intellij.psi.infos.MethodCandidateInfo;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.testFramework.IdeaTestUtil;
import org.jetbrains.annotations.NonNls;
@@ -88,6 +90,24 @@ public class Java8ExpressionsCheckTest extends LightDaemonAnalyzerTestCase {
doTestConfiguredFile(false, false, filePath);
}
public void testRejectCachedTopLevelSessionIfItCorrespondsToTheWrongOverload() throws Exception {
final String filePath = BASE_PATH + "/" + getTestName(false) + ".java";
configureByFile(filePath);
PsiMethodCallExpression methodCall =
PsiTreeUtil.getParentOfType(getFile().findElementAt(getEditor().getCaretModel().getOffset()), PsiMethodCallExpression.class);
assertNotNull(methodCall);
final PsiResolveHelper helper = JavaPsiFacade.getInstance(methodCall.getProject()).getResolveHelper();
CandidateInfo[] candidates = helper.getReferencedMethodCandidates(methodCall, false, true);
for (CandidateInfo candidate : candidates) {
if (candidate instanceof MethodCandidateInfo) {
//try to cache top level session
candidate.getSubstitutor();
}
}
doTestConfiguredFile(false, false, filePath);
}
private void doTestCachedUnresolved() {
configureByFile(BASE_PATH + "/" + getTestName(false) + ".java");
PsiMethodCallExpression callExpression =