clear diamond inference errors when overload resolution fails

This commit is contained in:
Anna.Kozlova
2016-04-28 11:36:54 +02:00
parent bebf4975e6
commit f36501444c
5 changed files with 104 additions and 56 deletions

View File

@@ -179,4 +179,6 @@ public abstract class PsiDiamondType extends PsiType {
}
return null;
}
public abstract JavaResolveResult getStaticFactory();
}

View File

@@ -497,7 +497,15 @@ public class MethodCandidateInfo extends CandidateInfo{
return clearErrorMessageInSubexpressions(((PsiConditionalExpression)expression).getElseExpression());
}
else if (expression instanceof PsiCallExpression) {
final JavaResolveResult result = ((PsiCallExpression)expression).resolveMethodGenerics();
final JavaResolveResult result;
if (expression instanceof PsiNewExpression) {
PsiDiamondType diamondType = PsiDiamondType.getDiamondType((PsiNewExpression)expression);
result = diamondType != null ? diamondType.getStaticFactory()
: ((PsiCallExpression)expression).resolveMethodGenerics();
}
else {
result = ((PsiCallExpression)expression).resolveMethodGenerics();
}
if (result instanceof MethodCandidateInfo) {
final String message = ((MethodCandidateInfo)result).getInferenceErrorMessage();
((MethodCandidateInfo)result).setInferenceError(null);

View File

@@ -22,7 +22,6 @@ import com.intellij.openapi.projectRoots.JavaSdkVersion;
import com.intellij.openapi.projectRoots.JavaVersionService;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession;
@@ -104,8 +103,7 @@ public class PsiDiamondTypeImpl extends PsiDiamondType {
@Override
public DiamondInferenceResult resolveInferredTypes() {
PsiElement typeElementWithDiamondTypeArgument = myTypeElement.getParent();
final PsiNewExpression newExpression = PsiTreeUtil.getParentOfType(typeElementWithDiamondTypeArgument, PsiNewExpression.class, true, PsiTypeElement.class);
final PsiNewExpression newExpression = getNewExpression();
if (newExpression == null) {
return PsiDiamondTypeImpl.DiamondInferenceResult.NULL_RESULT;
}
@@ -113,6 +111,17 @@ public class PsiDiamondTypeImpl extends PsiDiamondType {
return resolveInferredTypes(newExpression);
}
private PsiNewExpression getNewExpression() {
PsiElement typeElementWithDiamondTypeArgument = myTypeElement.getParent();
return PsiTreeUtil.getParentOfType(typeElementWithDiamondTypeArgument, PsiNewExpression.class, true, PsiTypeElement.class);
}
@Override
public JavaResolveResult getStaticFactory() {
final PsiNewExpression newExpression = getNewExpression();
return newExpression != null ? getStaticFactory(newExpression, newExpression) : null;
}
public static DiamondInferenceResult resolveInferredTypes(PsiNewExpression newExpression) {
return resolveInferredTypes(newExpression, newExpression);
}
@@ -145,41 +154,38 @@ public class PsiDiamondTypeImpl extends PsiDiamondType {
return inferenceResult;
}
private static JavaResolveResult getStaticFactory(final PsiNewExpression newExpression, final PsiElement context) {
return context == newExpression
? CachedValuesManager.getCachedValue(newExpression, new CachedValueProvider<JavaResolveResult>() {
@Nullable
@Override
public Result<JavaResolveResult> compute() {
return new Result<JavaResolveResult>(getStaticFactoryCandidateInfo(newExpression, newExpression),
PsiModificationTracker.MODIFICATION_COUNT);
}
})
: getStaticFactoryCandidateInfo(newExpression, context);
}
public static DiamondInferenceResult resolveInferredTypesNoCheck(final PsiNewExpression newExpression, final PsiElement context) {
final Ref<JavaResolveResult> staticFactoryRef = new Ref<JavaResolveResult>();
final JavaResolveResult staticFactoryCandidateInfo = getStaticFactory(newExpression, context);
if (staticFactoryCandidateInfo == null) {
return DiamondInferenceResult.NULL_RESULT;
}
final PsiSubstitutor inferredSubstitutor = ourDiamondGuard.doPreventingRecursion(context, false, new Computable<PsiSubstitutor>() {
@Override
public PsiSubstitutor compute() {
final JavaResolveResult staticFactoryCandidateInfo =
context == newExpression
? CachedValuesManager.getCachedValue(newExpression, new CachedValueProvider<JavaResolveResult>() {
@Nullable
@Override
public Result<JavaResolveResult> compute() {
return new Result<JavaResolveResult>(getStaticFactoryCandidateInfo(newExpression, newExpression), PsiModificationTracker.MODIFICATION_COUNT);
}
})
: getStaticFactoryCandidateInfo(newExpression, context);
staticFactoryRef.set(staticFactoryCandidateInfo);
if (staticFactoryCandidateInfo != null) {
PsiSubstitutor substitutor = staticFactoryCandidateInfo.getSubstitutor();
return staticFactoryCandidateInfo instanceof MethodCandidateInfo && ((MethodCandidateInfo)staticFactoryCandidateInfo).getInferenceErrorMessage() != null
? null : substitutor;
}
return null;
PsiSubstitutor substitutor = staticFactoryCandidateInfo.getSubstitutor();
return staticFactoryCandidateInfo instanceof MethodCandidateInfo &&
((MethodCandidateInfo)staticFactoryCandidateInfo).getInferenceErrorMessage() != null
? null : substitutor;
}
});
if (inferredSubstitutor == null) {
return DiamondInferenceResult.NULL_RESULT;
}
final JavaResolveResult staticFactoryInfo = staticFactoryRef.get();
if (staticFactoryInfo == null) {
LOG.error(inferredSubstitutor);
return DiamondInferenceResult.NULL_RESULT;
}
if (!(staticFactoryInfo instanceof MethodCandidateInfo)) {
if (!(staticFactoryCandidateInfo instanceof MethodCandidateInfo)) {
return DiamondInferenceResult.UNRESOLVED_CONSTRUCTOR;
}
@@ -189,7 +195,7 @@ public class PsiDiamondTypeImpl extends PsiDiamondType {
return DiamondInferenceResult.RAW_RESULT;
}
final PsiMethod staticFactory = ((MethodCandidateInfo)staticFactoryInfo).getElement();
final PsiMethod staticFactory = ((MethodCandidateInfo)staticFactoryCandidateInfo).getElement();
final PsiTypeParameter[] parameters = staticFactory.getTypeParameters();
final PsiElement staticFactoryContext = staticFactory.getContext();
final PsiClass psiClass = PsiTreeUtil.getContextOfType(staticFactoryContext, PsiClass.class, false);
@@ -223,31 +229,37 @@ public class PsiDiamondTypeImpl extends PsiDiamondType {
return result;
}
private static JavaResolveResult getStaticFactoryCandidateInfo(PsiNewExpression newExpression,
PsiElement context) {
final PsiExpressionList argumentList = newExpression.getArgumentList();
if (argumentList == null) {
//token expected diagnostic is provided by parser
return null;
}
private static JavaResolveResult getStaticFactoryCandidateInfo(final PsiNewExpression newExpression,
final PsiElement context) {
return ourDiamondGuard.doPreventingRecursion(context, false, new Computable<JavaResolveResult>() {
@Override
public JavaResolveResult compute() {
final JavaMethodsConflictResolver resolver = new JavaMethodsConflictResolver(argumentList, PsiUtil.getLanguageLevel(newExpression));
final JavaResolveResult[] result = collectStaticFactories(newExpression, resolver);
final PsiMethod staticFactory = result != null && result.length == 1 ? (PsiMethod)result[0].getElement() : null;
if (staticFactory == null) {
//additional diagnostics: inference fails due to unresolved constructor
return JavaResolveResult.EMPTY;
}
final PsiExpressionList argumentList = newExpression.getArgumentList();
if (argumentList == null) {
//token expected diagnostic is provided by parser
return null;
}
final MethodCandidateInfo staticFactoryCandidateInfo = createMethodCandidate(staticFactory, context, false, argumentList);
if (!staticFactory.isVarArgs()) {
return staticFactoryCandidateInfo;
}
final JavaMethodsConflictResolver resolver = new JavaMethodsConflictResolver(argumentList, PsiUtil.getLanguageLevel(newExpression));
final JavaResolveResult[] result = collectStaticFactories(newExpression, resolver);
final PsiMethod staticFactory = result != null && result.length == 1 ? (PsiMethod)result[0].getElement() : null;
if (staticFactory == null) {
//additional diagnostics: inference fails due to unresolved constructor
return JavaResolveResult.EMPTY;
}
final ArrayList<CandidateInfo> conflicts = new ArrayList<CandidateInfo>();
conflicts.add(staticFactoryCandidateInfo);
conflicts.add(createMethodCandidate(staticFactory, context, true, argumentList));
return resolver.resolveConflict(conflicts);
final MethodCandidateInfo staticFactoryCandidateInfo = createMethodCandidate(staticFactory, context, false, argumentList);
if (!staticFactory.isVarArgs()) {
return staticFactoryCandidateInfo;
}
final ArrayList<CandidateInfo> conflicts = new ArrayList<CandidateInfo>();
conflicts.add(staticFactoryCandidateInfo);
conflicts.add(createMethodCandidate(staticFactory, context, true, argumentList));
return resolver.resolveConflict(conflicts);
}
});
}
@Nullable

View File

@@ -0,0 +1,14 @@
import java.util.Collection;
class Test {
void m(StringBuilder builder){
builder.append(new Foo<>((Collection)null));
}
static class Foo<T> {
public Foo(Collection<? extends T> c) {}
public Foo(Foo<T> t) {}
}
}

View File

@@ -79,6 +79,10 @@ public class Java8ExpressionsCheckTest extends LightDaemonAnalyzerTestCase {
doTestAllMethodCallExpressions();
}
public void testObjectOverloadsWithDiamondsOverMultipleConstructors() throws Exception {
doTestAllMethodCallExpressions();
}
public void testNonCachingFolding() throws Exception {
final String filePath = BASE_PATH + "/" + getTestName(false) + ".java";
configureByFile(filePath);
@@ -149,11 +153,19 @@ public class Java8ExpressionsCheckTest extends LightDaemonAnalyzerTestCase {
assertNotNull("Failed inference for: " + expression.getText(), expression.getType());
}
final Collection<PsiReferenceParameterList> parameterLists = PsiTreeUtil.findChildrenOfType(getFile(), PsiReferenceParameterList.class);
for (PsiReferenceParameterList list : parameterLists) {
final Collection<PsiNewExpression> parameterLists = PsiTreeUtil.findChildrenOfType(getFile(), PsiNewExpression.class);
for (PsiNewExpression newExpression : parameterLists) {
getPsiManager().dropResolveCaches();
final PsiType[] arguments = list.getTypeArguments();
assertNotNull("Failed inference for: " + list.getParent().getText(), arguments);
final PsiType[] arguments = newExpression.getTypeArguments();
String failMessage = "Failed inference for: " + newExpression.getParent().getText();
assertNotNull(failMessage, arguments);
PsiDiamondType diamondType = PsiDiamondType.getDiamondType(newExpression);
if (diamondType != null) {
JavaResolveResult staticFactory = diamondType.getStaticFactory();
assertNotNull(staticFactory);
assertTrue(staticFactory instanceof MethodCandidateInfo);
assertNull(failMessage, ((MethodCandidateInfo)staticFactory).getInferenceErrorMessage());
}
}
}