mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-06 03:21:12 +07:00
new inference: process varargs as separate method candidate/separate phase
(cherry picked from commit fdd6f66268d29bb996a103f69180851b92947d21)
This commit is contained in:
@@ -56,7 +56,7 @@ public class JavaMethodResolveHelper {
|
||||
@Override
|
||||
protected MethodCandidateInfo createCandidateInfo(final PsiMethod method, final PsiSubstitutor substitutor,
|
||||
final boolean staticProblem,
|
||||
final boolean accessible) {
|
||||
final boolean accessible, final boolean varargs) {
|
||||
return JavaMethodResolveHelper.this
|
||||
.createCandidateInfo(method, substitutor, staticProblem, myCurrentFileContext, !accessible, argumentList, argumentTypes,
|
||||
languageLevel);
|
||||
|
||||
@@ -75,6 +75,10 @@ public class MethodCandidateInfo extends CandidateInfo{
|
||||
myLanguageLevel = languageLevel;
|
||||
}
|
||||
|
||||
public boolean isVarargs() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isApplicable(){
|
||||
return getApplicabilityLevel() != ApplicabilityLevel.NOT_APPLICABLE;
|
||||
}
|
||||
@@ -113,7 +117,7 @@ public class MethodCandidateInfo extends CandidateInfo{
|
||||
CURRENT_CANDIDATE.set(map);
|
||||
}
|
||||
final PsiMethod method = getElement();
|
||||
final CurrentCandidateProperties properties = new CurrentCandidateProperties(method, substitutor, false, true);
|
||||
final CurrentCandidateProperties properties = new CurrentCandidateProperties(method, substitutor, isVarargs(), true);
|
||||
final CurrentCandidateProperties alreadyThere = map.put(getMarkerList(), properties);
|
||||
try {
|
||||
properties.setSubstitutor(substitutor);
|
||||
@@ -122,7 +126,11 @@ public class MethodCandidateInfo extends CandidateInfo{
|
||||
return ApplicabilityLevel.NOT_APPLICABLE;
|
||||
}
|
||||
|
||||
return PsiUtil.getApplicabilityLevel(method, substitutor, argumentTypes, myLanguageLevel);
|
||||
final int applicabilityLevel = PsiUtil.getApplicabilityLevel(method, substitutor, argumentTypes, myLanguageLevel);
|
||||
if (!isVarargs() && applicabilityLevel < ApplicabilityLevel.FIXED_ARITY) {
|
||||
return ApplicabilityLevel.NOT_APPLICABLE;
|
||||
}
|
||||
return applicabilityLevel;
|
||||
}
|
||||
finally {
|
||||
if (alreadyThere == null) map.remove(getMarkerList());
|
||||
@@ -242,9 +250,10 @@ public class MethodCandidateInfo extends CandidateInfo{
|
||||
CURRENT_CANDIDATE.set(map);
|
||||
}
|
||||
final PsiMethod method = getElement();
|
||||
final CurrentCandidateProperties alreadyThere = map.put(getMarkerList(),
|
||||
new CurrentCandidateProperties(method, super.getSubstitutor(), false, //todo
|
||||
!includeReturnConstraint));
|
||||
final CurrentCandidateProperties alreadyThere = map.get(getMarkerList());
|
||||
if (alreadyThere == null) {
|
||||
map.put(getMarkerList(), new CurrentCandidateProperties(method, super.getSubstitutor(), isVarargs(), !includeReturnConstraint));
|
||||
}
|
||||
try {
|
||||
PsiTypeParameter[] typeParameters = method.getTypeParameters();
|
||||
|
||||
@@ -297,6 +306,16 @@ public class MethodCandidateInfo extends CandidateInfo{
|
||||
return myArgumentTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return super.equals(o) && isVarargs() == ((MethodCandidateInfo)o).isVarargs();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 31 * super.hashCode() + (isVarargs() ? 1 : 0);
|
||||
}
|
||||
|
||||
public static class CurrentCandidateProperties {
|
||||
private final PsiMethod myMethod;
|
||||
private PsiSubstitutor mySubstitutor;
|
||||
@@ -331,7 +350,7 @@ public class MethodCandidateInfo extends CandidateInfo{
|
||||
}
|
||||
|
||||
public boolean isApplicabilityCheck() {
|
||||
return myApplicabilityCheck && !ourOverloadGuard.currentStack().isEmpty();
|
||||
return myApplicabilityCheck;
|
||||
}
|
||||
|
||||
public void setApplicabilityCheck(boolean applicabilityCheck) {
|
||||
|
||||
@@ -148,7 +148,7 @@ public class PsiDiamondTypeImpl extends PsiDiamondType {
|
||||
}
|
||||
staticFactoryRef.set(staticFactory);
|
||||
|
||||
return inferTypeParametersForStaticFactory(staticFactory, newExpression, context);
|
||||
return inferTypeParametersForStaticFactory(staticFactory, newExpression, context, false);
|
||||
}
|
||||
});
|
||||
if (inferredSubstitutor == null) {
|
||||
@@ -297,12 +297,18 @@ public class PsiDiamondTypeImpl extends PsiDiamondType {
|
||||
|
||||
private static PsiSubstitutor inferTypeParametersForStaticFactory(@NotNull PsiMethod staticFactoryMethod,
|
||||
PsiNewExpression expression,
|
||||
final PsiElement parent) {
|
||||
final PsiElement parent,
|
||||
final boolean varargs) {
|
||||
final PsiExpressionList argumentList = expression.getArgumentList();
|
||||
if (argumentList != null) {
|
||||
final MethodCandidateInfo staticFactoryCandidateInfo =
|
||||
new MethodCandidateInfo(staticFactoryMethod, PsiSubstitutor.EMPTY, false, false, argumentList, parent,
|
||||
argumentList.getExpressionTypes(), null) {
|
||||
@Override
|
||||
public boolean isVarargs() {
|
||||
return varargs;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PsiElement getParent() {
|
||||
return parent;
|
||||
@@ -313,6 +319,9 @@ public class PsiDiamondTypeImpl extends PsiDiamondType {
|
||||
return parent instanceof PsiNewExpression ? ((PsiNewExpression)parent).getArgumentList() : super.getMarkerList();
|
||||
}
|
||||
};
|
||||
if (!varargs && staticFactoryMethod.isVarArgs() && staticFactoryCandidateInfo.getPertinentApplicabilityLevel() < MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY) {
|
||||
return inferTypeParametersForStaticFactory(staticFactoryMethod, expression, parent, true);
|
||||
}
|
||||
return staticFactoryCandidateInfo.getSubstitutor();
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -90,16 +90,25 @@ public class InferenceSession {
|
||||
}
|
||||
|
||||
public void initExpressionConstraints(PsiParameter[] parameters, PsiExpression[] args, PsiElement parent, PsiMethod method) {
|
||||
final MethodCandidateInfo.CurrentCandidateProperties currentProperties = getCurrentProperties(parent);
|
||||
initExpressionConstraints(parameters, args, parent, method, currentProperties != null && currentProperties.isVarargs());
|
||||
}
|
||||
|
||||
public void initExpressionConstraints(PsiParameter[] parameters,
|
||||
PsiExpression[] args,
|
||||
PsiElement parent,
|
||||
PsiMethod method,
|
||||
boolean varargs) {
|
||||
final MethodCandidateInfo.CurrentCandidateProperties currentProperties = getCurrentProperties(parent);
|
||||
if (method == null) {
|
||||
final MethodCandidateInfo.CurrentCandidateProperties pair = getCurrentProperties(parent);
|
||||
if (pair != null) {
|
||||
method = pair.getMethod();
|
||||
if (currentProperties != null) {
|
||||
method = currentProperties.getMethod();
|
||||
}
|
||||
}
|
||||
if (parameters.length > 0) {
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if (args[i] != null && isPertinentToApplicability(args[i], method)) {
|
||||
PsiType parameterType = getParameterType(parameters, args, i, mySiteSubstitutor);
|
||||
PsiType parameterType = getParameterType(parameters, i, mySiteSubstitutor, varargs);
|
||||
myConstraints.add(new ExpressionCompatibilityConstraint(args[i], parameterType));
|
||||
}
|
||||
}
|
||||
@@ -175,31 +184,11 @@ public class InferenceSession {
|
||||
return true;
|
||||
}
|
||||
|
||||
private PsiType getParameterType(PsiParameter[] parameters, PsiExpression[] args, int i, @Nullable PsiSubstitutor substitutor) {
|
||||
private static PsiType getParameterType(PsiParameter[] parameters, int i, @Nullable PsiSubstitutor substitutor, boolean varargs) {
|
||||
if (substitutor == null) return null;
|
||||
PsiType parameterType = substitutor.substitute(parameters[i < parameters.length ? i : parameters.length - 1].getType());
|
||||
if (parameterType instanceof PsiEllipsisType) {
|
||||
final PsiExpression arg = args[i];
|
||||
if (arg instanceof PsiNewExpression) {
|
||||
if (((PsiNewExpression)arg).getArrayDimensions().length == parameterType.getArrayDimensions() || ((PsiNewExpression)arg).getArrayInitializer() != null) {
|
||||
return parameterType;
|
||||
}
|
||||
}
|
||||
if (arg instanceof PsiCallExpression) {
|
||||
final PsiMethod method = ((PsiCallExpression)arg).resolveMethod();
|
||||
if (method != null) {
|
||||
final PsiType returnType = method.getReturnType();
|
||||
if (returnType != null && returnType.getArrayDimensions() == parameterType.getArrayDimensions()) {
|
||||
return parameterType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (args.length != parameters.length ||
|
||||
PsiPolyExpressionUtil.isPolyExpression(arg) ||
|
||||
arg != null && !(arg.getType() instanceof PsiArrayType)) {
|
||||
parameterType = ((PsiEllipsisType)parameterType).getComponentType();
|
||||
}
|
||||
if (parameterType instanceof PsiEllipsisType && varargs) {
|
||||
parameterType = ((PsiEllipsisType)parameterType).getComponentType();
|
||||
}
|
||||
return parameterType;
|
||||
}
|
||||
@@ -209,17 +198,18 @@ public class InferenceSession {
|
||||
return infer(null, null, null);
|
||||
}
|
||||
|
||||
private PsiSubstitutor tryToInfer(@Nullable PsiParameter[] parameters,
|
||||
@Nullable PsiExpression[] args,
|
||||
@Nullable PsiCallExpression parent,
|
||||
@Nullable MethodCandidateInfo.CurrentCandidateProperties properties) {
|
||||
@NotNull
|
||||
public PsiSubstitutor infer(@Nullable PsiParameter[] parameters,
|
||||
@Nullable PsiExpression[] args,
|
||||
@Nullable PsiElement parent) {
|
||||
final MethodCandidateInfo.CurrentCandidateProperties properties = getCurrentProperties(parent);
|
||||
if (!repeatInferencePhases(true)) {
|
||||
//inferred result would be checked as candidate won't be applicable
|
||||
return resolveSubset(myInferenceVariables.values(), mySiteSubstitutor);
|
||||
}
|
||||
|
||||
if (properties != null && !properties.isApplicabilityCheck()) {
|
||||
initReturnTypeConstraint(properties.getMethod(), parent);
|
||||
initReturnTypeConstraint(properties.getMethod(), (PsiCallExpression)parent);
|
||||
if (!repeatInferencePhases(true)) {
|
||||
return prepareSubstitution();
|
||||
}
|
||||
@@ -227,7 +217,7 @@ public class InferenceSession {
|
||||
if (parameters != null && args != null) {
|
||||
final Set<ConstraintFormula> additionalConstraints = new HashSet<ConstraintFormula>();
|
||||
if (parameters.length > 0) {
|
||||
collectAdditionalConstraints(parameters, args, properties.getMethod(), PsiSubstitutor.EMPTY, additionalConstraints);
|
||||
collectAdditionalConstraints(parameters, args, properties.getMethod(), PsiSubstitutor.EMPTY, additionalConstraints, properties.isVarargs());
|
||||
}
|
||||
|
||||
if (!additionalConstraints.isEmpty() && !proceedWithAdditionalConstraints(additionalConstraints)) {
|
||||
@@ -236,53 +226,6 @@ public class InferenceSession {
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void collectAdditionalConstraints(PsiParameter[] parameters,
|
||||
PsiExpression[] args,
|
||||
PsiMethod parentMethod,
|
||||
PsiSubstitutor siteSubstitutor,
|
||||
Set<ConstraintFormula> additionalConstraints) {
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if (args[i] != null) {
|
||||
PsiType parameterType = getParameterType(parameters, args, i, siteSubstitutor);
|
||||
if (!isPertinentToApplicability(args[i], parentMethod)) {
|
||||
additionalConstraints.add(new ExpressionCompatibilityConstraint(args[i], parameterType));
|
||||
}
|
||||
additionalConstraints.add(new CheckedExceptionCompatibilityConstraint(args[i], parameterType));
|
||||
if (args[i] instanceof PsiCallExpression) {
|
||||
//If the expression is a poly class instance creation expression (15.9) or a poly method invocation expression (15.12),
|
||||
//the set contains all constraint formulas that would appear in the set C when determining the poly expression's invocation type.
|
||||
final PsiCallExpression callExpression = (PsiCallExpression)args[i];
|
||||
final PsiExpressionList argumentList = callExpression.getArgumentList();
|
||||
if (argumentList != null) {
|
||||
final JavaResolveResult result = callExpression.resolveMethodGenerics();
|
||||
if (result instanceof MethodCandidateInfo) {
|
||||
final PsiMethod method = ((MethodCandidateInfo)result).getElement();
|
||||
LOG.assertTrue(method != null);
|
||||
final PsiExpression[] newArgs = argumentList.getExpressions();
|
||||
final PsiParameter[] newParams = method.getParameterList().getParameters();
|
||||
if (newParams.length > 0) {
|
||||
collectAdditionalConstraints(newParams, newArgs, method, ((MethodCandidateInfo)result).getSiteSubstitutor(), additionalConstraints);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PsiSubstitutor infer(@Nullable PsiParameter[] parameters,
|
||||
@Nullable PsiExpression[] args,
|
||||
@Nullable PsiElement parent) {
|
||||
final MethodCandidateInfo.CurrentCandidateProperties properties = getCurrentProperties(parent);
|
||||
final PsiSubstitutor subst = tryToInfer(parameters, args, parent instanceof PsiCallExpression ? ((PsiCallExpression)parent) : null, properties);
|
||||
if (subst != null) {
|
||||
return subst;
|
||||
}
|
||||
|
||||
final PsiSubstitutor substitutor = resolveBounds(myInferenceVariables.values(), mySiteSubstitutor);
|
||||
if (substitutor != null) {
|
||||
if (myContext != null) {
|
||||
@@ -302,6 +245,42 @@ public class InferenceSession {
|
||||
return prepareSubstitution();
|
||||
}
|
||||
|
||||
private static void collectAdditionalConstraints(PsiParameter[] parameters,
|
||||
PsiExpression[] args,
|
||||
PsiMethod parentMethod,
|
||||
PsiSubstitutor siteSubstitutor,
|
||||
Set<ConstraintFormula> additionalConstraints,
|
||||
boolean varargs) {
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if (args[i] != null) {
|
||||
PsiType parameterType = getParameterType(parameters, i, siteSubstitutor, varargs);
|
||||
if (!isPertinentToApplicability(args[i], parentMethod)) {
|
||||
additionalConstraints.add(new ExpressionCompatibilityConstraint(args[i], parameterType));
|
||||
}
|
||||
additionalConstraints.add(new CheckedExceptionCompatibilityConstraint(args[i], parameterType));
|
||||
if (args[i] instanceof PsiCallExpression) {
|
||||
//If the expression is a poly class instance creation expression (15.9) or a poly method invocation expression (15.12),
|
||||
//the set contains all constraint formulas that would appear in the set C when determining the poly expression's invocation type.
|
||||
final PsiCallExpression callExpression = (PsiCallExpression)args[i];
|
||||
final PsiExpressionList argumentList = callExpression.getArgumentList();
|
||||
if (argumentList != null) {
|
||||
final JavaResolveResult result = callExpression.resolveMethodGenerics();
|
||||
if (result instanceof MethodCandidateInfo) {
|
||||
final PsiMethod method = ((MethodCandidateInfo)result).getElement();
|
||||
LOG.assertTrue(method != null);
|
||||
final PsiExpression[] newArgs = argumentList.getExpressions();
|
||||
final PsiParameter[] newParams = method.getParameterList().getParameters();
|
||||
if (newParams.length > 0) {
|
||||
collectAdditionalConstraints(newParams, newArgs, method, ((MethodCandidateInfo)result).getSiteSubstitutor(),
|
||||
additionalConstraints, ((MethodCandidateInfo)result).isVarargs());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public PsiSubstitutor retrieveNonPrimitiveEqualsBounds(Collection<InferenceVariable> variables) {
|
||||
PsiSubstitutor substitutor = mySiteSubstitutor;
|
||||
for (InferenceVariable variable : variables) {
|
||||
@@ -486,7 +465,7 @@ public class InferenceSession {
|
||||
return false;
|
||||
}
|
||||
|
||||
private PsiType getTargetType(final PsiExpression context) {
|
||||
private static PsiType getTargetType(final PsiExpression context) {
|
||||
final PsiElement parent = PsiUtil.skipParenthesizedExprUp(context.getParent());
|
||||
if (parent instanceof PsiExpressionList) {
|
||||
PsiElement gParent = parent.getParent();
|
||||
@@ -498,16 +477,17 @@ public class InferenceSession {
|
||||
if (argumentList != null) {
|
||||
final MethodCandidateInfo.CurrentCandidateProperties properties = MethodCandidateInfo.getCurrentMethod(argumentList);
|
||||
if (properties != null && properties.isApplicabilityCheck()) {
|
||||
return getTypeByMethod(context, argumentList, properties.getMethod(), properties.getSubstitutor());
|
||||
return getTypeByMethod(context, argumentList, properties.getMethod(), properties.isVarargs(), properties.getSubstitutor());
|
||||
}
|
||||
final JavaResolveResult result = ((PsiCallExpression)gParent).resolveMethodGenerics();
|
||||
final boolean varargs = properties != null && properties.isVarargs() || result instanceof MethodCandidateInfo && ((MethodCandidateInfo)result).isVarargs();
|
||||
return getTypeByMethod(context, argumentList, result.getElement(),
|
||||
varargs,
|
||||
PsiResolveHelper.ourGraphGuard.doPreventingRecursion(argumentList.getParent(), false,
|
||||
new Computable<PsiSubstitutor>() {
|
||||
@Override
|
||||
public PsiSubstitutor compute() {
|
||||
return result
|
||||
.getSubstitutor();
|
||||
return result.getSubstitutor();
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -531,9 +511,11 @@ public class InferenceSession {
|
||||
return null;
|
||||
}
|
||||
|
||||
private PsiType getTypeByMethod(PsiExpression context,
|
||||
PsiExpressionList argumentList,
|
||||
PsiElement parentMethod, PsiSubstitutor substitutor) {
|
||||
private static PsiType getTypeByMethod(PsiExpression context,
|
||||
PsiExpressionList argumentList,
|
||||
PsiElement parentMethod,
|
||||
boolean varargs,
|
||||
PsiSubstitutor substitutor) {
|
||||
if (parentMethod instanceof PsiMethod) {
|
||||
final PsiParameter[] parameters = ((PsiMethod)parentMethod).getParameterList().getParameters();
|
||||
if (parameters.length == 0) return null;
|
||||
@@ -545,7 +527,7 @@ public class InferenceSession {
|
||||
}
|
||||
final int i = ArrayUtilRt.find(args, arg);
|
||||
if (i < 0) return null;
|
||||
return getParameterType(parameters, args, i, substitutor);
|
||||
return getParameterType(parameters, i, substitutor, varargs);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm
|
||||
if (method != null) {
|
||||
final PsiExpression[] args = argumentList.getExpressions();
|
||||
final PsiParameter[] parameters = method.getParameterList().getParameters();
|
||||
callSession.initExpressionConstraints(parameters, args, myExpression, method);
|
||||
callSession.initExpressionConstraints(parameters, args, myExpression, method, resolveResult instanceof MethodCandidateInfo && ((MethodCandidateInfo)resolveResult).isVarargs());
|
||||
}
|
||||
final boolean accepted = callSession.repeatInferencePhases(true);
|
||||
if (!accepted) {
|
||||
|
||||
@@ -445,20 +445,31 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase
|
||||
final PsiConflictResolver conflictResolver = createResolver(qualifierResolveResult, interfaceMethod, signature);
|
||||
final MethodCandidatesProcessor processor =
|
||||
new MethodCandidatesProcessor(reference, getContainingFile(), new PsiConflictResolver[] {conflictResolver}, new SmartList<CandidateInfo>()) {
|
||||
@Override
|
||||
protected boolean acceptVarargs() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MethodCandidateInfo createCandidateInfo(final PsiMethod method,
|
||||
final PsiSubstitutor substitutor,
|
||||
final boolean staticProblem,
|
||||
final boolean accessible) {
|
||||
final boolean accessible,
|
||||
final boolean varargs) {
|
||||
final PsiExpressionList argumentList = getArgumentList();
|
||||
final PsiType[] typeParameters = reference.getTypeParameters();
|
||||
return new MethodCandidateInfo(method, substitutor, !accessible, staticProblem, argumentList, myCurrentFileContext,
|
||||
argumentList != null ? argumentList.getExpressionTypes() : null, typeParameters.length > 0 ? typeParameters : null,
|
||||
getLanguageLevel()) {
|
||||
@Override
|
||||
public boolean isVarargs() {
|
||||
return varargs;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public PsiSubstitutor inferTypeArguments(@NotNull ParameterTypeInferencePolicy policy, boolean includeReturnConstraint) {
|
||||
return inferTypeArguments(false); //includeReturnConstraint == vararg todo
|
||||
return inferTypeArguments(varargs);
|
||||
}
|
||||
|
||||
public PsiSubstitutor inferTypeArguments(boolean varargs) {
|
||||
@@ -517,9 +528,6 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase
|
||||
}
|
||||
|
||||
if (!session.repeatInferencePhases(false)) {
|
||||
if (method.isVarArgs() && !varargs) {
|
||||
return inferTypeArguments(true);
|
||||
}
|
||||
return substitutor;
|
||||
}
|
||||
|
||||
@@ -600,13 +608,14 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase
|
||||
mySignature = signature;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getPertinentApplicabilityLevel(MethodCandidateInfo conflict) {
|
||||
return conflict.isVarargs() ? MethodCandidateInfo.ApplicabilityLevel.VARARGS : MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public CandidateInfo resolveConflict(@NotNull List<CandidateInfo> conflicts) {
|
||||
return resolveConflict(conflicts, false);
|
||||
}
|
||||
|
||||
public CandidateInfo resolveConflict(@NotNull List<CandidateInfo> conflicts, boolean varargs) {
|
||||
if (mySignature == null) return null;
|
||||
|
||||
checkSameSignatures(conflicts);
|
||||
@@ -627,6 +636,7 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase
|
||||
final PsiSubstitutor substitutor = conflict.getSubstitutor();
|
||||
final PsiType[] signatureParameterTypes2 = psiMethod.getSignature(substitutor).getParameterTypes();
|
||||
|
||||
final boolean varargs = ((MethodCandidateInfo)conflict).isVarargs();
|
||||
if (varargs && (!psiMethod.isVarArgs() || myFunctionalMethodVarArgs)) continue;
|
||||
|
||||
if ((varargs || parameterTypes.length == signatureParameterTypes2.length) &&
|
||||
@@ -655,19 +665,12 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase
|
||||
}
|
||||
}
|
||||
|
||||
checkSpecifics(firstCandidates,
|
||||
varargs ? MethodCandidateInfo.ApplicabilityLevel.VARARGS : MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY, myLanguageLevel);
|
||||
|
||||
checkSpecifics(secondCandidates,
|
||||
varargs ? MethodCandidateInfo.ApplicabilityLevel.VARARGS : MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY, myLanguageLevel);
|
||||
|
||||
final int acceptedCount = firstCandidates.size() + secondCandidates.size();
|
||||
if (acceptedCount == 1) {
|
||||
if (resolveConflicts(firstCandidates, secondCandidates, MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY)) {
|
||||
return !firstCandidates.isEmpty() ? firstCandidates.get(0) : secondCandidates.get(0);
|
||||
}
|
||||
|
||||
if (!varargs) {
|
||||
return resolveConflict(conflicts, true);
|
||||
if (resolveConflicts(firstCandidates, secondCandidates, MethodCandidateInfo.ApplicabilityLevel.VARARGS)) {
|
||||
return !firstCandidates.isEmpty() ? firstCandidates.get(0) : secondCandidates.get(0);
|
||||
}
|
||||
|
||||
conflicts.clear();
|
||||
@@ -676,6 +679,17 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean resolveConflicts(List<CandidateInfo> firstCandidates, List<CandidateInfo> secondCandidates, int applicabilityLevel) {
|
||||
|
||||
checkApplicability(firstCandidates);
|
||||
checkSpecifics(firstCandidates, applicabilityLevel, myLanguageLevel);
|
||||
|
||||
checkApplicability(secondCandidates);
|
||||
checkSpecifics(secondCandidates, applicabilityLevel, myLanguageLevel);
|
||||
|
||||
return firstCandidates.size() + secondCandidates.size() == 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean nonComparable(CandidateInfo method, CandidateInfo conflict) {
|
||||
if (method == conflict) return true;
|
||||
|
||||
@@ -392,12 +392,12 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
|
||||
}
|
||||
|
||||
@MethodCandidateInfo.ApplicabilityLevelConstant
|
||||
private static int checkApplicability(List<CandidateInfo> conflicts) {
|
||||
protected int checkApplicability(List<CandidateInfo> conflicts) {
|
||||
@MethodCandidateInfo.ApplicabilityLevelConstant int maxApplicabilityLevel = 0;
|
||||
boolean toFilter = false;
|
||||
for (CandidateInfo conflict : conflicts) {
|
||||
ProgressManager.checkCanceled();
|
||||
@MethodCandidateInfo.ApplicabilityLevelConstant final int level = ((MethodCandidateInfo)conflict).getPertinentApplicabilityLevel();
|
||||
@MethodCandidateInfo.ApplicabilityLevelConstant final int level = getPertinentApplicabilityLevel((MethodCandidateInfo)conflict);
|
||||
if (maxApplicabilityLevel > 0 && maxApplicabilityLevel != level) {
|
||||
toFilter = true;
|
||||
}
|
||||
@@ -410,7 +410,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
|
||||
for (Iterator<CandidateInfo> iterator = conflicts.iterator(); iterator.hasNext();) {
|
||||
ProgressManager.checkCanceled();
|
||||
CandidateInfo info = iterator.next();
|
||||
final int level = ((MethodCandidateInfo)info).getPertinentApplicabilityLevel();
|
||||
final int level = getPertinentApplicabilityLevel((MethodCandidateInfo)info);
|
||||
if (level < maxApplicabilityLevel) {
|
||||
iterator.remove();
|
||||
}
|
||||
@@ -420,6 +420,10 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
|
||||
return maxApplicabilityLevel;
|
||||
}
|
||||
|
||||
protected int getPertinentApplicabilityLevel(MethodCandidateInfo conflict) {
|
||||
return conflict.getPertinentApplicabilityLevel();
|
||||
}
|
||||
|
||||
private static int getCheckAccessLevel(MethodCandidateInfo method){
|
||||
boolean visible = method.isAccessible();
|
||||
return visible ? 1 : 0;
|
||||
@@ -570,6 +574,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
|
||||
if (abstract2 && !abstract1) {
|
||||
return Specifics.FIRST;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8) && myArgumentsList instanceof PsiExpressionList && (typeParameters1.length == 0 || typeParameters2.length == 0)) {
|
||||
@@ -661,6 +666,12 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{
|
||||
return raw1 ? Specifics.SECOND : Specifics.FIRST;
|
||||
}
|
||||
|
||||
final boolean varargs1 = info1.isVarargs();
|
||||
final boolean varargs2 = info2.isVarargs();
|
||||
if (varargs1 ^ varargs2) {
|
||||
return varargs1 ? Specifics.SECOND : Specifics.FIRST;
|
||||
}
|
||||
|
||||
return Specifics.NEITHER;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.intellij.psi.infos.CandidateInfo;
|
||||
import com.intellij.psi.infos.MethodCandidateInfo;
|
||||
import com.intellij.psi.scope.PsiConflictResolver;
|
||||
import com.intellij.psi.scope.conflictResolvers.DuplicateConflictResolver;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.SmartList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -54,13 +55,20 @@ public class MethodCandidatesProcessor extends MethodsProcessor{
|
||||
myPlace, myAccessClass, myCurrentFileContext, myPlaceFile) &&
|
||||
!isShadowed(method);
|
||||
if (isAccepted(method)) {
|
||||
add(createCandidateInfo(method, substitutor, staticProblem, isAccessible));
|
||||
add(createCandidateInfo(method, substitutor, staticProblem, isAccessible, false));
|
||||
if (acceptVarargs() && method.isVarArgs() && PsiUtil.isLanguageLevel8OrHigher(myPlace)) {
|
||||
add(createCandidateInfo(method, substitutor, staticProblem, isAccessible, true));
|
||||
}
|
||||
myHasAccessibleStaticCorrectCandidate |= isAccessible && !staticProblem;
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean acceptVarargs() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected MethodCandidateInfo createCandidateInfo(final PsiMethod method, final PsiSubstitutor substitutor,
|
||||
final boolean staticProblem, final boolean accessible) {
|
||||
final boolean staticProblem, final boolean accessible, final boolean varargs) {
|
||||
final PsiExpressionList argumentList = getArgumentList();
|
||||
return new MethodCandidateInfo(method, substitutor, !accessible, staticProblem, argumentList, myCurrentFileContext,
|
||||
null, getTypeArguments(), getLanguageLevel()) {
|
||||
@@ -68,6 +76,11 @@ public class MethodCandidatesProcessor extends MethodsProcessor{
|
||||
public PsiType[] getArgumentTypes() {
|
||||
return getExpressionTypes(argumentList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVarargs() {
|
||||
return varargs;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -63,4 +63,9 @@ public class MethodResolverProcessor extends MethodCandidatesProcessor {
|
||||
public boolean execute(@NotNull PsiElement element, ResolveState state) {
|
||||
return !myStopAcceptingCandidates && super.execute(element, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean acceptVarargs() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ class Test {
|
||||
}
|
||||
|
||||
static void foo2(final A<? extends Integer> bar) {
|
||||
bar._<error descr="'_(capture<? extends java.lang.Integer>...)' in 'Test.A' cannot be applied to '(java.lang.String)'">("")</error>;
|
||||
bar._<error descr="Cannot resolve method '_(java.lang.String)'">("")</error>;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ public class Sample {
|
||||
<B> B bar(G<B> gb) {return null;}
|
||||
|
||||
void f(G1 g1) {
|
||||
<error descr="Incompatible types. Found: 'B', required: 'Sample.G<java.lang.String>'">G<String> l11 = bar(g1);</error>
|
||||
<error descr="Incompatible types. Found: 'B', required: 'java.lang.String'">String l1 = bar(g1);</error>
|
||||
<error descr="Incompatible types. Found: 'java.lang.Object', required: 'Sample.G<java.lang.String>'">G<String> l11 = bar(g1);</error>
|
||||
<error descr="Incompatible types. Found: 'java.lang.Object', required: 'java.lang.String'">String l1 = bar(g1);</error>
|
||||
Object o = bar(g1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
class A<T> {
|
||||
A(T... t) {
|
||||
}
|
||||
|
||||
{
|
||||
A<String> a = new A<>("a", "b");
|
||||
foo(new A<>("", ""));
|
||||
bar(new A<>("", ""));
|
||||
bar(new A<>(get()));
|
||||
//bar(new A<>(get( ), ""));
|
||||
}
|
||||
|
||||
void foo(A<String> s) {}
|
||||
<T> void bar(A<T> s) {}
|
||||
|
||||
<K> K get() {return null;}
|
||||
|
||||
<M> A<M> s(M... m) {
|
||||
return null;
|
||||
}
|
||||
|
||||
{
|
||||
bar(s(get()));
|
||||
bar(s(get(), ""));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
abstract class Im {
|
||||
public static final Class[] EMPTY_CLASS_ARRAY = new Class[0];
|
||||
public abstract <T> T createProxy(final Class<T> superClass, final Class... otherInterfaces);
|
||||
|
||||
void f(Class<?> implementation, Class rawType, boolean isInterface) {
|
||||
createProxy(implementation, isInterface ? new Class[]{rawType} : EMPTY_CLASS_ARRAY);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
public class Test {
|
||||
class Test {
|
||||
|
||||
interface II {
|
||||
int _();
|
||||
|
||||
@@ -31,6 +31,10 @@ public class Diamond8HighlightingTest extends LightDaemonAnalyzerTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testVarargs() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTest() throws Exception {
|
||||
doTestNewInference(BASE_PATH + "/" + getTestName(false) + ".java", false, false);
|
||||
}
|
||||
|
||||
@@ -176,6 +176,10 @@ public class GraphInferenceHighlightingTest extends LightDaemonAnalyzerTestCase
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testVarargsOnNonPertinentPlace() throws Exception {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void doTest() throws Exception {
|
||||
doTest(false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user