use of com.intellij.psi.infos.MethodCandidateInfo in project intellij-community by JetBrains.
the class JavaMethodsConflictResolver method checkSameSignatures.
protected void checkSameSignatures(@NotNull List<CandidateInfo> conflicts, FactoryMap<MethodCandidateInfo, PsiSubstitutor> map) {
// candidates should go in order of class hierarchy traversal
// in order for this to work
Map<MethodSignature, CandidateInfo> signatures = new THashMap<>(conflicts.size());
Set<PsiMethod> superMethods = new HashSet<>();
for (CandidateInfo conflict : conflicts) {
final PsiMethod method = ((MethodCandidateInfo) conflict).getElement();
final PsiClass containingClass = method.getContainingClass();
final boolean isInterface = containingClass != null && containingClass.isInterface();
for (HierarchicalMethodSignature methodSignature : method.getHierarchicalMethodSignature().getSuperSignatures()) {
final PsiMethod superMethod = methodSignature.getMethod();
if (!isInterface) {
superMethods.add(superMethod);
} else {
final PsiClass aClass = superMethod.getContainingClass();
if (aClass != null && !CommonClassNames.JAVA_LANG_OBJECT.equals(aClass.getQualifiedName())) {
superMethods.add(superMethod);
}
}
}
}
nextConflict: for (int i = 0; i < conflicts.size(); i++) {
ProgressManager.checkCanceled();
CandidateInfo info = conflicts.get(i);
PsiMethod method = (PsiMethod) info.getElement();
if (!method.hasModifierProperty(PsiModifier.STATIC) && superMethods.contains(method)) {
conflicts.remove(i);
i--;
continue;
}
PsiClass class1 = method.getContainingClass();
PsiSubstitutor infoSubstitutor = getSubstitutor((MethodCandidateInfo) info, map);
MethodSignature signature = method.getSignature(infoSubstitutor);
CandidateInfo existing = signatures.get(signature);
if (existing == null) {
signatures.put(signature, info);
continue;
}
PsiMethod existingMethod = (PsiMethod) existing.getElement();
PsiClass existingClass = existingMethod.getContainingClass();
if (class1 != null && existingClass != null) {
//prefer interface methods to methods from Object
if (class1.isInterface() && CommonClassNames.JAVA_LANG_OBJECT.equals(existingClass.getQualifiedName())) {
signatures.put(signature, info);
continue;
} else if (existingClass.isInterface() && CommonClassNames.JAVA_LANG_OBJECT.equals(class1.getQualifiedName())) {
conflicts.remove(info);
i--;
continue;
}
}
if (method == existingMethod) {
PsiElement scope1 = info.getCurrentFileResolveScope();
PsiElement scope2 = existing.getCurrentFileResolveScope();
if (scope1 instanceof PsiClass && scope2 instanceof PsiClass && PsiTreeUtil.isAncestor(scope1, scope2, true) && !existing.isAccessible()) {
//prefer methods from outer class to inaccessible base class methods
signatures.put(signature, info);
continue;
}
}
// filter out methods with incorrect inferred bounds (for unrelated methods only)
boolean existingTypeParamAgree = areTypeParametersAgree(existing);
boolean infoTypeParamAgree = areTypeParametersAgree(info);
if (existingTypeParamAgree && !infoTypeParamAgree && !PsiSuperMethodImplUtil.isSuperMethodSmart(method, existingMethod)) {
conflicts.remove(i);
i--;
continue;
}
if (!existingTypeParamAgree && infoTypeParamAgree && !PsiSuperMethodImplUtil.isSuperMethodSmart(existingMethod, method)) {
signatures.put(signature, info);
int index = conflicts.indexOf(existing);
conflicts.remove(index);
i--;
continue;
}
if (InheritanceUtil.isInheritorOrSelf(class1, existingClass, true) || InheritanceUtil.isInheritorOrSelf(existingClass, class1, true)) {
PsiParameter[] parameters = method.getParameterList().getParameters();
final PsiParameter[] existingParameters = existingMethod.getParameterList().getParameters();
for (int i1 = 0, parametersLength = parameters.length; i1 < parametersLength; i1++) {
if (parameters[i1].getType() instanceof PsiArrayType && !(existingParameters[i1].getType() instanceof PsiArrayType)) {
//prefer more specific type
signatures.put(signature, info);
continue nextConflict;
}
}
PsiType returnType1 = method.getReturnType();
PsiType returnType2 = existingMethod.getReturnType();
if (returnType1 != null && returnType2 != null) {
returnType1 = infoSubstitutor.substitute(returnType1);
returnType2 = getSubstitutor((MethodCandidateInfo) existing, map).substitute(returnType2);
if (!returnType1.equals(returnType2) && returnType1.isAssignableFrom(returnType2)) {
conflicts.remove(i);
i--;
continue;
}
}
// prefer derived class
signatures.put(signature, info);
} else {
final PsiMethodCallExpression methodCallExpression = PsiTreeUtil.getParentOfType(myArgumentsList, PsiMethodCallExpression.class);
if (methodCallExpression != null) {
final PsiReferenceExpression expression = methodCallExpression.getMethodExpression();
final PsiExpression qualifierExpression = expression.getQualifierExpression();
PsiClass currentClass;
if (qualifierExpression != null) {
currentClass = PsiUtil.resolveClassInClassTypeOnly(qualifierExpression.getType());
} else {
currentClass = PsiTreeUtil.getParentOfType(expression, PsiClass.class);
}
if (currentClass != null && existingClass != null && class1 != null) {
final PsiSubstitutor eSubstitutor = TypeConversionUtil.getMaybeSuperClassSubstitutor(existingClass, currentClass, PsiSubstitutor.EMPTY, null);
final PsiSubstitutor cSubstitutor = TypeConversionUtil.getMaybeSuperClassSubstitutor(class1, currentClass, PsiSubstitutor.EMPTY, null);
if (eSubstitutor != null && cSubstitutor != null && MethodSignatureUtil.areSignaturesEqual(existingMethod.getSignature(eSubstitutor), method.getSignature(cSubstitutor))) {
final PsiType returnType = eSubstitutor.substitute(existingMethod.getReturnType());
final PsiType returnType1 = cSubstitutor.substitute(method.getReturnType());
if (returnType != null && returnType1 != null && !returnType1.equals(returnType)) {
if (TypeConversionUtil.isAssignable(returnType, returnType1, false)) {
if (class1.isInterface() && !existingClass.isInterface())
continue;
conflicts.remove(existing);
} else {
if (!TypeConversionUtil.isAssignable(returnType1, returnType, false))
continue;
conflicts.remove(i);
}
i--;
break;
}
}
}
}
}
}
}
use of com.intellij.psi.infos.MethodCandidateInfo in project intellij-community by JetBrains.
the class JavaMethodsConflictResolver method checkSpecifics.
public void checkSpecifics(@NotNull List<CandidateInfo> conflicts, @MethodCandidateInfo.ApplicabilityLevelConstant int applicabilityLevel, FactoryMap<MethodCandidateInfo, PsiSubstitutor> map, @NotNull LanguageLevel languageLevel) {
final boolean applicable = applicabilityLevel > MethodCandidateInfo.ApplicabilityLevel.NOT_APPLICABLE;
int conflictsCount = conflicts.size();
// Specifics
if (applicable) {
final CandidateInfo[] newConflictsArray = conflicts.toArray(new CandidateInfo[conflicts.size()]);
for (int i = 1; i < conflictsCount; i++) {
final CandidateInfo method = newConflictsArray[i];
for (int j = 0; j < i; j++) {
ProgressManager.checkCanceled();
final CandidateInfo conflict = newConflictsArray[j];
if (nonComparable(method, conflict, applicabilityLevel == MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY))
continue;
switch(isMoreSpecific((MethodCandidateInfo) method, (MethodCandidateInfo) conflict, applicabilityLevel, map, languageLevel)) {
case FIRST:
conflicts.remove(conflict);
break;
case SECOND:
conflicts.remove(method);
break;
case NEITHER:
break;
}
}
}
}
}
use of com.intellij.psi.infos.MethodCandidateInfo in project intellij-community by JetBrains.
the class JavaMethodsConflictResolver method checkAccessStaticLevels.
protected static void checkAccessStaticLevels(@NotNull List<CandidateInfo> conflicts, boolean checkAccessible) {
int conflictsCount = conflicts.size();
int maxCheckLevel = -1;
int[] checkLevels = new int[conflictsCount];
int index = 0;
for (final CandidateInfo conflict : conflicts) {
ProgressManager.checkCanceled();
final MethodCandidateInfo method = (MethodCandidateInfo) conflict;
final int level = checkAccessible ? getCheckAccessLevel(method) : getCheckStaticLevel(method);
checkLevels[index++] = level;
maxCheckLevel = Math.max(maxCheckLevel, level);
}
for (int i = conflictsCount - 1; i >= 0; i--) {
// check for level
if (checkLevels[i] < maxCheckLevel) {
conflicts.remove(i);
}
}
}
use of com.intellij.psi.infos.MethodCandidateInfo in project intellij-community by JetBrains.
the class PsiMethodReferenceExpressionImpl method isAcceptable.
@Override
public boolean isAcceptable(PsiType left) {
if (left instanceof PsiIntersectionType) {
for (PsiType conjunct : ((PsiIntersectionType) left).getConjuncts()) {
if (isAcceptable(conjunct))
return true;
}
return false;
}
final PsiExpressionList argsList = PsiTreeUtil.getParentOfType(this, PsiExpressionList.class);
final boolean isExact = isExact();
if (MethodCandidateInfo.ourOverloadGuard.currentStack().contains(argsList)) {
final MethodCandidateInfo.CurrentCandidateProperties candidateProperties = MethodCandidateInfo.getCurrentMethod(argsList);
if (candidateProperties != null) {
final PsiMethod method = candidateProperties.getMethod();
if (isExact && !InferenceSession.isPertinentToApplicability(this, method)) {
return true;
}
if (LambdaUtil.isPotentiallyCompatibleWithTypeParameter(this, argsList, method)) {
return true;
}
}
}
left = FunctionalInterfaceParameterizationUtil.getGroundTargetType(left);
if (!isPotentiallyCompatible(left)) {
return false;
}
if (MethodCandidateInfo.ourOverloadGuard.currentStack().contains(argsList)) {
if (!isExact) {
return true;
}
}
// A method reference is congruent with a function type if the following are true:
// The function type identifies a single compile-time declaration corresponding to the reference.
// One of the following is true:
// i)The return type of the function type is void.
// ii)The return type of the function type is R;
// the result of applying capture conversion (5.1.10) to the return type of the invocation type (15.12.2.6) of the chosen declaration is R',
// where R is the target type that may be used to infer R'; neither R nor R' is void; and R' is compatible with R in an assignment context.
Map<PsiElement, PsiType> map = LambdaUtil.getFunctionalTypeMap();
final JavaResolveResult result;
try {
if (map.put(this, left) != null) {
return false;
}
result = advancedResolve(false);
} finally {
map.remove(this);
}
if (result instanceof MethodCandidateInfo && !((MethodCandidateInfo) result).isApplicable()) {
return false;
}
final PsiElement resolve = result.getElement();
if (resolve == null) {
return false;
}
return PsiMethodReferenceUtil.isReturnTypeCompatible(this, result, left);
}
use of com.intellij.psi.infos.MethodCandidateInfo in project intellij-community by JetBrains.
the class Java8ExpressionsCheckTest method testCachingOfResultsDuringCandidatesIteration.
public void testCachingOfResultsDuringCandidatesIteration() throws Exception {
configureByFile(BASE_PATH + "/" + getTestName(false) + ".java");
final Collection<PsiMethodCallExpression> methodCallExpressions = PsiTreeUtil.findChildrenOfType(getFile(), PsiMethodCallExpression.class);
final PsiResolveHelper helper = JavaPsiFacade.getInstance(getProject()).getResolveHelper();
for (PsiMethodCallExpression expression : methodCallExpressions) {
CandidateInfo[] candidates = helper.getReferencedMethodCandidates(expression, false, true);
PsiExpressionList argumentList = expression.getArgumentList();
PsiExpression[] args = argumentList.getExpressions();
for (JavaResolveResult result : candidates) {
if (result instanceof MethodCandidateInfo) {
final MethodCandidateInfo info = (MethodCandidateInfo) result;
MethodCandidateInfo.ourOverloadGuard.doPreventingRecursion(argumentList, false, () -> info.inferTypeArguments(DefaultParameterTypeInferencePolicy.INSTANCE, args, true));
}
}
PsiMethodCallExpression parentCall = PsiTreeUtil.getParentOfType(expression, PsiMethodCallExpression.class, true);
if (parentCall != null) {
JavaResolveResult result = parentCall.getMethodExpression().advancedResolve(false);
if (result instanceof MethodCandidateInfo) {
assertNull(((MethodCandidateInfo) result).getInferenceErrorMessage());
}
}
}
}
Aggregations