diamonds: resolve conflicts based on type params from constructor and containing class (IDEA-123518)

This commit is contained in:
Anna Kozlova
2014-04-25 18:38:39 +02:00
parent f3e1d968b8
commit baccb31d7e
4 changed files with 65 additions and 18 deletions
@@ -22,8 +22,13 @@ 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;
import com.intellij.psi.scope.PsiConflictResolver;
import com.intellij.psi.scope.conflictResolvers.JavaMethodsConflictResolver;
import com.intellij.psi.scope.processor.MethodCandidatesProcessor;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
@@ -33,9 +38,7 @@ import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.*;
/**
* @author anna
@@ -139,10 +142,7 @@ public class PsiDiamondTypeImpl extends PsiDiamondType {
final PsiSubstitutor inferredSubstitutor = ourDiamondGuard.doPreventingRecursion(context, false, new Computable<PsiSubstitutor>() {
@Override
public PsiSubstitutor compute() {
final PsiMethod constructor = findConstructor(psiClass, newExpression);
PsiTypeParameter[] params = getAllTypeParams(constructor, psiClass);
final PsiMethod staticFactory = generateStaticFactory(constructor, psiClass, params, newExpression.getClassReference());
final PsiMethod staticFactory = findConstructorStaticFactory(psiClass, newExpression);
if (staticFactory == null) {
return null;
}
@@ -177,14 +177,42 @@ public class PsiDiamondTypeImpl extends PsiDiamondType {
@Nullable
private static PsiMethod findConstructor(PsiClass containingClass, PsiNewExpression newExpression) {
private static PsiMethod findConstructorStaticFactory(final PsiClass containingClass, PsiNewExpression newExpression) {
final PsiExpressionList argumentList = newExpression.getArgumentList();
final Project project = newExpression.getProject();
final JavaPsiFacade facade = JavaPsiFacade.getInstance(project);
final PsiResolveHelper resolveHelper = facade.getResolveHelper();
final JavaResolveResult result =
resolveHelper.resolveConstructor(facade.getElementFactory().createType(containingClass, PsiSubstitutor.EMPTY), argumentList, argumentList);
return (PsiMethod)result.getElement();
if (argumentList == null) return null;
final LanguageLevel languageLevel = PsiUtil.getLanguageLevel(newExpression);
final List<CandidateInfo> conflicts = new ArrayList<CandidateInfo>();
PsiMethod[] constructors = containingClass.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) {
@Override
protected boolean isAccepted(PsiMethod candidate) {
return true;
}
@Override
protected PsiClass getContainingClass(PsiMethod method) {
return containingClass;
}
};
processor.setArgumentList(argumentList);
for (PsiMethod constructor : constructors) {
final PsiTypeParameter[] params = getAllTypeParams(constructor, containingClass);
final PsiMethod staticFactory = generateStaticFactory(constructor, containingClass, 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;
}
@Nullable
@@ -220,7 +248,11 @@ public class PsiDiamondTypeImpl extends PsiDiamondType {
PsiTypeParameter[] params,
PsiJavaCodeReferenceElement reference) {
final StringBuilder buf = new StringBuilder();
buf.append("public static ");
buf.append(constructor != null ? constructor.getModifierList().getText() : containingClass.getModifierList().getText());
if (buf.length() > 0) {
buf.append(" ");
}
buf.append("static ");
buf.append("<");
buf.append(StringUtil.join(params, new Function<PsiTypeParameter, String>() {
@Override
@@ -51,7 +51,7 @@ public class MethodCandidatesProcessor extends MethodsProcessor{
}
public void addMethod(@NotNull PsiMethod method, final PsiSubstitutor substitutor, final boolean staticProblem) {
final boolean isAccessible = JavaResolveUtil.isAccessible(method, method.getContainingClass(), method.getModifierList(),
final boolean isAccessible = JavaResolveUtil.isAccessible(method, getContainingClass(method), method.getModifierList(),
myPlace, myAccessClass, myCurrentFileContext, myPlaceFile) &&
!isShadowed(method);
if (isAccepted(method)) {
@@ -63,6 +63,10 @@ public class MethodCandidatesProcessor extends MethodsProcessor{
}
}
protected PsiClass getContainingClass(PsiMethod method) {
return method.getContainingClass();
}
protected boolean acceptVarargs() {
return false;
}
@@ -106,10 +110,10 @@ public class MethodCandidatesProcessor extends MethodsProcessor{
if (!candidate.isConstructor()) return false;
if (myAccessClass == null) return true;
if (myAccessClass instanceof PsiAnonymousClass) {
final PsiClass containingClass = candidate.getContainingClass();
final PsiClass containingClass = getContainingClass(candidate);
return containingClass != null && containingClass.equals(myAccessClass.getSuperClass());
}
return myAccessClass.isEquivalentTo(candidate.getContainingClass());
return myAccessClass.isEquivalentTo(getContainingClass(candidate));
}
}
@@ -0,0 +1,10 @@
import java.util.*;
class XTest {
public void setStuff(String stuff) {
setStuff(new ArrayList<>(Arrays.asList(stuff)));
}
private void setStuff(List<String> stuff) {
}
}
@@ -98,6 +98,7 @@ public class LightAdvHighlightingJdk7Test extends LightDaemonAnalyzerTestCase {
public void testDiamondNeg13() { doTest(false, false); }
public void testDiamondNeg14() { doTest(false, false); }
public void testDiamondMisc() { doTest(false, false); }
public void testMultipleConstructors() { doTest(false, false); }
public void testHighlightInaccessibleFromClassModifierList() { doTest(false, false); }
public void testInnerInTypeArguments() { doTest(false, false); }