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 57f9e5f19f46..a9e55041a5af 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 @@ -19,7 +19,6 @@ import com.intellij.lang.ASTNode; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.TextRange; -import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.impl.PsiManagerEx; import com.intellij.psi.impl.source.resolve.ParameterTypeInferencePolicy; @@ -306,6 +305,12 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase return this; } + @Override + public boolean isConstructor() { + final PsiElement element = getReferenceNameElement(); + return element instanceof PsiKeyword && PsiKeyword.NEW.equals(element.getText()); + } + @Override public String toString() { return "PsiMethodReferenceExpression:" + getText(); @@ -373,16 +378,8 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase final MethodReferenceConflictResolver conflictResolver = new MethodReferenceConflictResolver(qualifierResolveResult, signature, interfaceMethod != null && interfaceMethod.isVarArgs()); - final PsiConflictResolver[] resolvers; - if (signature != null) { - final PsiType[] parameterTypes = signature.getParameterTypes(); - resolvers = new PsiConflictResolver[]{conflictResolver, new MethodRefsSpecificResolver(parameterTypes, PsiUtil.getLanguageLevel(PsiMethodReferenceExpressionImpl.this))}; - } - else { - resolvers = new PsiConflictResolver[]{conflictResolver}; - } final MethodCandidatesProcessor processor = - new MethodCandidatesProcessor(PsiMethodReferenceExpressionImpl.this, getContainingFile(), resolvers, new SmartList()) { + new MethodCandidatesProcessor(PsiMethodReferenceExpressionImpl.this, getContainingFile(), new PsiConflictResolver[] {conflictResolver}, new SmartList()) { @Override protected MethodCandidateInfo createCandidateInfo(final PsiMethod method, final PsiSubstitutor substitutor, @@ -500,13 +497,14 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase .createType(containingClass, isRawSubst ? PsiSubstitutor.EMPTY : substitutor); } - private class MethodReferenceConflictResolver implements PsiConflictResolver { + private class MethodReferenceConflictResolver extends JavaMethodsConflictResolver { private final MethodSignature mySignature; private final PsiMethodReferenceUtil.QualifierResolveResult myQualifierResolveResult; private final boolean myFunctionalMethodVarArgs; private MethodReferenceConflictResolver(PsiMethodReferenceUtil.QualifierResolveResult qualifierResolveResult, @Nullable MethodSignature signature, boolean varArgs) { + super(PsiMethodReferenceExpressionImpl.this, signature != null ? signature.getParameterTypes() : PsiType.EMPTY_ARRAY, PsiUtil.getLanguageLevel(PsiMethodReferenceExpressionImpl.this)); myQualifierResolveResult = qualifierResolveResult; myFunctionalMethodVarArgs = varArgs; mySignature = signature; @@ -515,83 +513,101 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase @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); + checkAccessStaticLevels(conflicts, true); + final PsiType[] parameterTypes = mySignature.getParameterTypes(); boolean hasReceiver = PsiMethodReferenceUtil.hasReceiver(parameterTypes, myQualifierResolveResult, PsiMethodReferenceExpressionImpl.this); final List firstCandidates = new ArrayList(); final List secondCandidates = new ArrayList(); + for (CandidateInfo conflict : conflicts) { if (!(conflict instanceof MethodCandidateInfo)) continue; final PsiMethod psiMethod = ((MethodCandidateInfo)conflict).getElement(); if (psiMethod == null) continue; - PsiSubstitutor substitutor = conflict.getSubstitutor(); + + final PsiSubstitutor substitutor = conflict.getSubstitutor(); final PsiType[] signatureParameterTypes2 = psiMethod.getSignature(substitutor).getParameterTypes(); - boolean varArgs = psiMethod.isVarArgs(); + if (varargs && (!psiMethod.isVarArgs() || myFunctionalMethodVarArgs)) continue; - if (parameterTypes.length == signatureParameterTypes2.length && - isCorrectAssignment(signatureParameterTypes2, parameterTypes, substitutor, false, 0)) { + if ((varargs || parameterTypes.length == signatureParameterTypes2.length) && + isCorrectAssignment(signatureParameterTypes2, parameterTypes, substitutor, varargs, 0)) { firstCandidates.add(conflict); - varArgs = false; } if (hasReceiver && - parameterTypes.length == signatureParameterTypes2.length + 1 && - isCorrectAssignment(signatureParameterTypes2, parameterTypes, substitutor, false, 1)) { + (varargs || parameterTypes.length == signatureParameterTypes2.length + 1) && + isCorrectAssignment(signatureParameterTypes2, parameterTypes, substitutor, varargs, 1)) { secondCandidates.add(conflict); - varArgs = false; - } - - if (varArgs && !myFunctionalMethodVarArgs) { - - if (isCorrectAssignment(signatureParameterTypes2, parameterTypes, substitutor, true, 0)) { - firstCandidates.add(conflict); - } - - if (hasReceiver && isCorrectAssignment(signatureParameterTypes2, parameterTypes, substitutor, true, 1)) { - secondCandidates.add(conflict); - } } } - final boolean identifierRef = getReferenceNameElement() instanceof PsiIdentifier; - //If the first search produces a static method, and no non-static method is applicable for the second search, then the result of the first search is the compile-time declaration. - final List firstCandidateInfos = myQualifierResolveResult.isReferenceTypeQualified() && identifierRef ? filterStaticCorrectCandidates(firstCandidates, true) : firstCandidates; + checkSpecifics(firstCandidates, + varargs ? MethodCandidateInfo.ApplicabilityLevel.VARARGS : MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY, myLanguageLevel); - //If the second search produces a non-static method, and no static method is applicable for the first search, then the result of the second search is the compile-time declaration. - final List secondCandidateInfos = myQualifierResolveResult.isReferenceTypeQualified() && identifierRef ? filterStaticCorrectCandidates(secondCandidates, false) : secondCandidates; + checkSpecifics(secondCandidates, + varargs ? MethodCandidateInfo.ApplicabilityLevel.VARARGS : MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY, myLanguageLevel); - final int acceptedCount = firstCandidateInfos.size() + secondCandidateInfos.size(); + if (myQualifierResolveResult.isReferenceTypeQualified() && getReferenceNameElement() instanceof PsiIdentifier) { + //If the first search produces a static method, and no non-static method is applicable for the second search, then the result of the first search is the compile-time declaration. + filterStaticCorrectCandidates(firstCandidates, true); + + //If the second search produces a non-static method, and no static method is applicable for the first search, then the result of the second search is the compile-time declaration. + filterStaticCorrectCandidates(secondCandidates, false); + } + + final int acceptedCount = firstCandidates.size() + secondCandidates.size(); if (acceptedCount == 1) { - return !firstCandidateInfos.isEmpty() ? firstCandidateInfos.get(0) : secondCandidateInfos.get(0); + return !firstCandidates.isEmpty() ? firstCandidates.get(0) : secondCandidates.get(0); + } + + if (!varargs) { + return resolveConflict(conflicts, true); } conflicts.clear(); - firstCandidateInfos.addAll(secondCandidateInfos); - conflicts.addAll(firstCandidateInfos); + firstCandidates.addAll(secondCandidates); + conflicts.addAll(firstCandidates); return null; } + @Override + protected boolean nonComparable(CandidateInfo method, CandidateInfo conflict) { + if (method == conflict) return true; + PsiElement psiElement = method.getElement(); + PsiElement conflictElement = conflict.getElement(); + if (psiElement instanceof PsiMethod && conflictElement instanceof PsiMethod) { + if (((PsiMethod)psiElement).getParameterList().getParametersCount() != + ((PsiMethod)conflictElement).getParameterList().getParametersCount()) { + return true; + } + } + return false; + } + /** * 15.13.1 */ - private List filterStaticCorrectCandidates(List firstCandidates, - boolean shouldBeStatic) { - final List result = new ArrayList(); - for (CandidateInfo candidate : firstCandidates) { - final CandidateInfo candidateInfo = firstCandidates.get(0); - final PsiElement element = candidateInfo.getElement(); + private void filterStaticCorrectCandidates(List firstCandidates, + boolean shouldBeStatic) { + for (Iterator iterator = firstCandidates.iterator(); iterator.hasNext(); ) { + final PsiElement element = iterator.next().getElement(); if (element instanceof PsiMethod) { final boolean isStatic = ((PsiMethod)element).hasModifierProperty(PsiModifier.STATIC); - if (shouldBeStatic && isStatic || !shouldBeStatic && !isStatic) { - result.add(candidate); + if (shouldBeStatic && !isStatic || !shouldBeStatic && isStatic) { + iterator.remove(); } } } - return result; } private boolean isCorrectAssignment(PsiType[] signatureParameterTypes2, @@ -615,67 +631,5 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase return true; } } - - private class MethodRefsSpecificResolver extends JavaMethodsConflictResolver { - public MethodRefsSpecificResolver(@NotNull PsiType[] parameterTypes, @NotNull LanguageLevel languageLevel) { - super(PsiMethodReferenceExpressionImpl.this, parameterTypes, languageLevel); - } - - @Override - public CandidateInfo resolveConflict(@NotNull List conflicts) { - checkSameSignatures(conflicts); - if (conflicts.size() == 1) return conflicts.get(0); - - checkAccessStaticLevels(conflicts, true); - if (conflicts.size() == 1) return conflicts.get(0); - - boolean varargs = false; - boolean fixedArity = false; - for (CandidateInfo conflict : conflicts) { - final PsiElement psiElement = conflict.getElement(); - if (psiElement instanceof PsiMethod) { - final boolean isVarargs = ((PsiMethod)psiElement).isVarArgs(); - if (isVarargs) { - varargs = true; - } else { - fixedArity = true; - } - if (varargs && fixedArity) break; - } - } - if (varargs && fixedArity) { - for (Iterator iterator = conflicts.iterator(); iterator.hasNext(); ) { - CandidateInfo conflict = iterator.next(); - final PsiElement element = conflict.getElement(); - if (element instanceof PsiMethod && ((PsiMethod)element).isVarArgs()) iterator.remove(); - } - } - - checkSpecifics(conflicts, - varargs ? MethodCandidateInfo.ApplicabilityLevel.VARARGS : MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY, - myLanguageLevel); - return conflicts.size() == 1 ? conflicts.get(0) : null; - } - - @Override - protected boolean nonComparable(CandidateInfo method, CandidateInfo conflict) { - if (method == conflict) return true; - PsiElement psiElement = method.getElement(); - PsiElement conflictElement = conflict.getElement(); - if (psiElement instanceof PsiMethod && conflictElement instanceof PsiMethod) { - if (((PsiMethod)psiElement).getParameterList().getParametersCount() != - ((PsiMethod)conflictElement).getParameterList().getParametersCount()) { - return true; - } - } - return false; - } - } - } - - @Override - public boolean isConstructor() { - final PsiElement element = getReferenceNameElement(); - return element instanceof PsiKeyword && PsiKeyword.NEW.equals(element.getText()); } }