diff --git a/java/java-impl/src/com/intellij/psi/resolve/JavaMethodResolveHelper.java b/java/java-impl/src/com/intellij/psi/resolve/JavaMethodResolveHelper.java index 2a17536550d1..c89ac7281c60 100644 --- a/java/java-impl/src/com/intellij/psi/resolve/JavaMethodResolveHelper.java +++ b/java/java-impl/src/com/intellij/psi/resolve/JavaMethodResolveHelper.java @@ -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); diff --git a/java/java-psi-api/src/com/intellij/psi/infos/MethodCandidateInfo.java b/java/java-psi-api/src/com/intellij/psi/infos/MethodCandidateInfo.java index c87d6b796124..ab15a5bd50b7 100644 --- a/java/java-psi-api/src/com/intellij/psi/infos/MethodCandidateInfo.java +++ b/java/java-psi-api/src/com/intellij/psi/infos/MethodCandidateInfo.java @@ -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) { diff --git a/java/java-psi-impl/src/com/intellij/psi/PsiDiamondTypeImpl.java b/java/java-psi-impl/src/com/intellij/psi/PsiDiamondTypeImpl.java index e7ebfca1a4e1..028a577e33b4 100644 --- a/java/java-psi-impl/src/com/intellij/psi/PsiDiamondTypeImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/PsiDiamondTypeImpl.java @@ -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 { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java index 31332b704b54..0017275b7207 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java @@ -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 additionalConstraints = new HashSet(); 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 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 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 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() { @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; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java index ebcbda6a2926..ff462cef03a8 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java @@ -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) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java index a6bff8e9777d..c3d78414d566 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java @@ -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()) { + @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 conflicts) { - return resolveConflict(conflicts, false); - } - - public CandidateInfo resolveConflict(@NotNull List 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 firstCandidates, List 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; diff --git a/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java b/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java index 9a2504c5ad2b..e758c1d72f98 100644 --- a/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java +++ b/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java @@ -392,12 +392,12 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ } @MethodCandidateInfo.ApplicabilityLevelConstant - private static int checkApplicability(List conflicts) { + protected int checkApplicability(List 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 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; } diff --git a/java/java-psi-impl/src/com/intellij/psi/scope/processor/MethodCandidatesProcessor.java b/java/java-psi-impl/src/com/intellij/psi/scope/processor/MethodCandidatesProcessor.java index 8607ff43c60e..e44dfc7a9040 100644 --- a/java/java-psi-impl/src/com/intellij/psi/scope/processor/MethodCandidatesProcessor.java +++ b/java/java-psi-impl/src/com/intellij/psi/scope/processor/MethodCandidatesProcessor.java @@ -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; + } }; } diff --git a/java/java-psi-impl/src/com/intellij/psi/scope/processor/MethodResolverProcessor.java b/java/java-psi-impl/src/com/intellij/psi/scope/processor/MethodResolverProcessor.java index 396d9b3b60d0..b73f87b72ce4 100644 --- a/java/java-psi-impl/src/com/intellij/psi/scope/processor/MethodResolverProcessor.java +++ b/java/java-psi-impl/src/com/intellij/psi/scope/processor/MethodResolverProcessor.java @@ -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; + } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA91626.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA91626.java index ff29729bc977..d8db681dd0de 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA91626.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA91626.java @@ -11,7 +11,7 @@ class Test { } static void foo2(final A bar) { - bar._(""); + bar._(""); } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/constraints/UncheckedBoundsWithErasure.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/constraints/UncheckedBoundsWithErasure.java index a106da75fa7e..49753a7bcdac 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/constraints/UncheckedBoundsWithErasure.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/constraints/UncheckedBoundsWithErasure.java @@ -7,8 +7,8 @@ public class Sample { B bar(G gb) {return null;} void f(G1 g1) { - G l11 = bar(g1); - String l1 = bar(g1); + G l11 = bar(g1); + String l1 = bar(g1); Object o = bar(g1); } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/diamond/Varargs.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/diamond/Varargs.java new file mode 100644 index 000000000000..2826e5802e91 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/diamond/Varargs.java @@ -0,0 +1,26 @@ +class A { + A(T... t) { + } + + { + A a = new A<>("a", "b"); + foo(new A<>("", "")); + bar(new A<>("", "")); + bar(new A<>(get())); + //bar(new A<>(get( ), "")); + } + + void foo(A s) {} + void bar(A s) {} + + K get() {return null;} + + A s(M... m) { + return null; + } + + { + bar(s(get())); + bar(s(get(), "")); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/VarargsOnNonPertinentPlace.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/VarargsOnNonPertinentPlace.java new file mode 100644 index 000000000000..4d10bd47b5eb --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/graphInference/VarargsOnNonPertinentPlace.java @@ -0,0 +1,8 @@ +abstract class Im { + public static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; + public abstract T createProxy(final Class superClass, final Class... otherInterfaces); + + void f(Class implementation, Class rawType, boolean isInterface) { + createProxy(implementation, isInterface ? new Class[]{rawType} : EMPTY_CLASS_ARRAY); + } +} diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguityReturnValueResolution1.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguityReturnValueResolution1.java index fab979466120..a6abf3db299a 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguityReturnValueResolution1.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/lambda/highlighting/AmbiguityReturnValueResolution1.java @@ -1,4 +1,4 @@ -public class Test { +class Test { interface II { int _(); diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/Diamond8HighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/Diamond8HighlightingTest.java index ca4133b79172..eb73906a5f15 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/Diamond8HighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/Diamond8HighlightingTest.java @@ -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); } diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java index 3b4c606ab2ca..dbf3e3703992 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/lambda/GraphInferenceHighlightingTest.java @@ -176,6 +176,10 @@ public class GraphInferenceHighlightingTest extends LightDaemonAnalyzerTestCase doTest(); } + public void testVarargsOnNonPertinentPlace() throws Exception { + doTest(); + } + private void doTest() throws Exception { doTest(false); }