mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
new inference: method refs overload resolution compact
This commit is contained in:
+64
-110
@@ -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<CandidateInfo>()) {
|
||||
new MethodCandidatesProcessor(PsiMethodReferenceExpressionImpl.this, getContainingFile(), new PsiConflictResolver[] {conflictResolver}, new SmartList<CandidateInfo>()) {
|
||||
@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<CandidateInfo> conflicts) {
|
||||
return resolveConflict(conflicts, false);
|
||||
}
|
||||
|
||||
public CandidateInfo resolveConflict(@NotNull List<CandidateInfo> 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<CandidateInfo> firstCandidates = new ArrayList<CandidateInfo>();
|
||||
final List<CandidateInfo> secondCandidates = new ArrayList<CandidateInfo>();
|
||||
|
||||
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<CandidateInfo> 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<CandidateInfo> 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<CandidateInfo> filterStaticCorrectCandidates(List<CandidateInfo> firstCandidates,
|
||||
boolean shouldBeStatic) {
|
||||
final List<CandidateInfo> result = new ArrayList<CandidateInfo>();
|
||||
for (CandidateInfo candidate : firstCandidates) {
|
||||
final CandidateInfo candidateInfo = firstCandidates.get(0);
|
||||
final PsiElement element = candidateInfo.getElement();
|
||||
private void filterStaticCorrectCandidates(List<CandidateInfo> firstCandidates,
|
||||
boolean shouldBeStatic) {
|
||||
for (Iterator<CandidateInfo> 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<CandidateInfo> 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<CandidateInfo> 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());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user