proceed static factories instead of constructors to calculate expected types when diamonds are used (IDEA-153520)

This commit is contained in:
Anna.Kozlova
2016-03-24 18:14:17 +01:00
parent 778f7f84df
commit 7712f6e443
5 changed files with 74 additions and 22 deletions
@@ -23,11 +23,13 @@ import com.intellij.openapi.util.NullableComputable;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.codeStyle.VariableKind;
import com.intellij.psi.impl.PsiDiamondTypeUtil;
import com.intellij.psi.impl.source.resolve.CompletionParameterTypeInferencePolicy;
import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy;
import com.intellij.psi.impl.source.resolve.ParameterTypeInferencePolicy;
import com.intellij.psi.infos.CandidateInfo;
import com.intellij.psi.infos.MethodCandidateInfo;
import com.intellij.psi.scope.conflictResolvers.DuplicateConflictResolver;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PsiShortNamesCache;
import com.intellij.psi.search.searches.DeepestSuperMethodsSearch;
@@ -595,6 +597,14 @@ public class ExpectedTypesProvider {
private void getExpectedArgumentsTypesForNewExpression(@NotNull final PsiNewExpression newExpr,
@NotNull final PsiExpressionList list) {
if (PsiDiamondTypeUtil.hasDiamond(newExpr)) {
final JavaResolveResult[] candidates = PsiDiamondTypeImpl.collectStaticFactories(newExpr, DuplicateConflictResolver.INSTANCE);
if (candidates != null) {
final PsiExpressionList argumentList = newExpr.getArgumentList();
Collections.addAll(myResult, getExpectedArgumentTypesForMethodCall(ContainerUtil.map(candidates, (candidate) -> (CandidateInfo)candidate, CandidateInfo.EMPTY_ARRAY), argumentList, myExpr, myForCompletion));
}
return;
}
PsiType newType = newExpr.getType();
if (newType instanceof PsiClassType) {
JavaResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(newType);
@@ -24,7 +24,6 @@ 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.pom.java.LanguageLevel;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.infos.CandidateInfo;
import com.intellij.psi.infos.MethodCandidateInfo;
@@ -221,13 +220,9 @@ public class PsiDiamondTypeImpl extends PsiDiamondType {
return null;
}
final PsiClass psiClass = findClass(newExpression);
if (psiClass == null) {
//should not happens: unresolved class reference would be first and inference won't start
return null;
}
final PsiMethod staticFactory = findConstructorStaticFactory(psiClass, newExpression);
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;
@@ -238,7 +233,6 @@ public class PsiDiamondTypeImpl extends PsiDiamondType {
return staticFactoryCandidateInfo;
}
final JavaMethodsConflictResolver resolver = new JavaMethodsConflictResolver(argumentList, PsiUtil.getLanguageLevel(argumentList));
final ArrayList<CandidateInfo> conflicts = new ArrayList<CandidateInfo>();
conflicts.add(staticFactoryCandidateInfo);
conflicts.add(createMethodCandidate(staticFactory, context, true, argumentList));
@@ -246,20 +240,27 @@ public class PsiDiamondTypeImpl extends PsiDiamondType {
}
@Nullable
private static PsiMethod findConstructorStaticFactory(final PsiClass containingClass, PsiNewExpression newExpression) {
final PsiExpressionList argumentList = newExpression.getArgumentList();
if (argumentList == null) return null;
public static JavaResolveResult[] collectStaticFactories(PsiNewExpression newExpression, final PsiConflictResolver... conflictResolvers) {
PsiExpressionList argumentList = newExpression.getArgumentList();
if (argumentList == null) {
return null;
}
final LanguageLevel languageLevel = PsiUtil.getLanguageLevel(newExpression);
final List<CandidateInfo> conflicts = new ArrayList<CandidateInfo>();
PsiMethod[] constructors = containingClass.getConstructors();
final PsiClass psiClass = findClass(newExpression);
if (psiClass == null) {
//should not happens: unresolved class reference would be first and inference won't start
return null;
}
final List<CandidateInfo> candidates = new ArrayList<CandidateInfo>();
PsiMethod[] constructors = psiClass.getConstructors();
if (constructors.length == 0) {
//default constructor
constructors = new PsiMethod[] {null};
}
final PsiConflictResolver[] conflictResolvers = {new JavaMethodsConflictResolver(argumentList, languageLevel)};
final MethodCandidatesProcessor processor = new MethodCandidatesProcessor(argumentList, argumentList.getContainingFile(), conflictResolvers, conflicts) {
final MethodCandidatesProcessor
processor = new MethodCandidatesProcessor(argumentList, argumentList.getContainingFile(), conflictResolvers, candidates) {
@Override
protected boolean isAccepted(PsiMethod candidate) {
return true;
@@ -267,7 +268,7 @@ public class PsiDiamondTypeImpl extends PsiDiamondType {
@Override
protected PsiClass getContainingClass(PsiMethod method) {
return containingClass;
return psiClass;
}
@Override
@@ -278,15 +279,14 @@ public class PsiDiamondTypeImpl extends PsiDiamondType {
processor.setArgumentList(argumentList);
for (PsiMethod constructor : constructors) {
final PsiTypeParameter[] params = getAllTypeParams(constructor, containingClass);
final PsiMethod staticFactory = generateStaticFactory(constructor, containingClass, params, newExpression.getClassReference());
final PsiTypeParameter[] params = getAllTypeParams(constructor, psiClass);
final PsiMethod staticFactory = generateStaticFactory(constructor, psiClass, params, newExpression.getClassReference());
if (staticFactory != null) {
processor.add(staticFactory, PsiSubstitutor.EMPTY);
}
}
final JavaResolveResult[] result = processor.getResult();
return result.length == 1 ? (PsiMethod)result[0].getElement() : null;
return processor.getResult();
}
@Nullable
@@ -0,0 +1,20 @@
class Outer <U, V> {
Outer(Foo<? super U> a) {}
Outer(Bar<? super U, ? extends V> a) {}
{
Outer<String, String> o = new Outer<>(new Foo<String>() {
@Override
public void m() {
}
});
}
}
interface Foo<A> {
void m();
}
interface Bar<A, B> {}
@@ -0,0 +1,15 @@
class Outer <U, V> {
Outer(Foo<? super U> a) {}
Outer(Bar<? super U, ? extends V> a) {}
{
Outer<String, String> o = new Outer<>(new F<caret>);
}
}
interface Foo<A> {
void m();
}
interface Bar<A, B> {}
@@ -153,6 +153,13 @@ public void testConvertToObjectStream() {
checkResultByFile("/" + getTestName(false) + "-out.java");
}
public void testInsideNewExpressionWithDiamondAndOverloadConstructors() throws Exception {
configureByTestName();
myFixture.complete(CompletionType.SMART, 1);
myFixture.type('\n');
checkResultByFile("/" + getTestName(false) + "-out.java");
}
public void testCollectorsToList() {
doTest(false);
}