@Nullable private static MethodSignature getSignatureForInheritor( @NotNull PsiMethod methodFromSuperClass, @NotNull GrTypeDefinition inheritor) { final PsiClass clazz = methodFromSuperClass.getContainingClass(); if (clazz == null) return null; PsiSubstitutor superSubstitutor = TypeConversionUtil.getClassSubstitutor(clazz, inheritor, PsiSubstitutor.EMPTY); if (superSubstitutor == null) return null; return methodFromSuperClass.getSignature(superSubstitutor); }
static boolean isInheritorOrSelf(PsiMethod inheritorCandidate, PsiMethod base) { PsiClass aClass = inheritorCandidate.getContainingClass(); PsiClass bClass = base.getContainingClass(); if (aClass == null || bClass == null) return false; PsiSubstitutor substitutor = TypeConversionUtil.getClassSubstitutor(bClass, aClass, PsiSubstitutor.EMPTY); return substitutor != null && MethodSignatureUtil.findMethodBySignature( bClass, inheritorCandidate.getSignature(substitutor), false) == base; }
public static String checkReturnType( PsiMethodReferenceExpression expression, JavaResolveResult result, PsiType functionalInterfaceType) { final PsiElement resolve = result.getElement(); if (resolve instanceof PsiMethod) { final PsiClass containingClass = ((PsiMethod) resolve).getContainingClass(); LOG.assertTrue(containingClass != null); PsiSubstitutor subst = result.getSubstitutor(); PsiClass qContainingClass = getQualifierResolveResult(expression).getContainingClass(); if (qContainingClass != null && isReceiverType(functionalInterfaceType, containingClass, (PsiMethod) resolve)) { subst = TypeConversionUtil.getClassSubstitutor(containingClass, qContainingClass, subst); LOG.assertTrue(subst != null); } final PsiType interfaceReturnType = LambdaUtil.getFunctionalInterfaceReturnType(functionalInterfaceType); PsiType returnType = PsiTypesUtil.patchMethodGetClassReturnType( expression, expression, (PsiMethod) resolve, null, PsiUtil.getLanguageLevel(expression)); if (returnType == null) { returnType = ((PsiMethod) resolve).getReturnType(); } PsiType methodReturnType = subst.substitute(returnType); if (interfaceReturnType != null && interfaceReturnType != PsiType.VOID) { if (methodReturnType == null) { methodReturnType = JavaPsiFacade.getElementFactory(expression.getProject()) .createType(containingClass, subst); } if (!TypeConversionUtil.isAssignable(interfaceReturnType, methodReturnType, false)) { return "Bad return type in method reference: cannot convert " + methodReturnType.getCanonicalText() + " to " + interfaceReturnType.getCanonicalText(); } } } return null; }
@Nullable public static PsiMethod findMethodBySuperMethod( @NotNull PsiClass aClass, @NotNull PsiMethod method, final boolean checkBases) { List<Pair<PsiMethod, PsiSubstitutor>> pairs = aClass.findMethodsAndTheirSubstitutorsByName(method.getName(), checkBases); for (Pair<PsiMethod, PsiSubstitutor> pair : pairs) { PsiMethod candidate = pair.first; PsiSubstitutor substitutor = pair.second; MethodSignature candidateSignature = candidate.getSignature(substitutor); final PsiClass methodClass = method.getContainingClass(); final PsiClass candidateClass = candidate.getContainingClass(); if (methodClass == null || candidateClass == null) continue; PsiSubstitutor superSubstitutor = TypeConversionUtil.getClassSubstitutor(methodClass, candidateClass, substitutor); if (superSubstitutor == null) continue; MethodSignature superSignature = method.getSignature(superSubstitutor); if (isSubsignature(superSignature, candidateSignature)) return candidate; } return null; }
public static boolean isReceiverType( PsiType receiverType, @Nullable PsiClass containingClass, PsiSubstitutor psiSubstitutor) { if (containingClass != null) { receiverType = getExpandedType(receiverType, containingClass); } final PsiClassType.ClassResolveResult resolveResult = PsiUtil.resolveGenericsClassInType(receiverType); final PsiClass receiverClass = resolveResult.getElement(); if (receiverClass != null && isReceiverType(receiverClass, containingClass)) { if (emptyOrRaw(containingClass, psiSubstitutor)) { return true; } final PsiSubstitutor derivedSubstitutor = TypeConversionUtil.getClassSubstitutor(containingClass, receiverClass, psiSubstitutor); return derivedSubstitutor != null && TypeConversionUtil.isAssignable( JavaPsiFacade.getElementFactory(containingClass.getProject()) .createType(containingClass, derivedSubstitutor), receiverType); } return false; }
@Nullable public static String getSuspiciousMethodCallMessage( @NotNull PsiMethodCallExpression methodCall, PsiType argType, boolean reportConvertibleMethodCalls, @NotNull List<PsiMethod> patternMethods, @NotNull IntArrayList indices) { final PsiReferenceExpression methodExpression = methodCall.getMethodExpression(); final PsiExpression qualifier = methodExpression.getQualifierExpression(); if (qualifier == null || qualifier instanceof PsiThisExpression || qualifier instanceof PsiSuperExpression) return null; if (argType instanceof PsiPrimitiveType) { argType = ((PsiPrimitiveType) argType).getBoxedType(methodCall); } if (!(argType instanceof PsiClassType)) return null; final JavaResolveResult resolveResult = methodExpression.advancedResolve(false); PsiMethod calleeMethod = (PsiMethod) resolveResult.getElement(); if (calleeMethod == null) return null; PsiMethod contextMethod = PsiTreeUtil.getParentOfType(methodCall, PsiMethod.class); //noinspection SynchronizationOnLocalVariableOrMethodParameter synchronized (patternMethods) { if (patternMethods.isEmpty()) { setupPatternMethods( methodCall.getManager(), methodCall.getResolveScope(), patternMethods, indices); } } for (int i = 0; i < patternMethods.size(); i++) { PsiMethod patternMethod = patternMethods.get(i); if (!patternMethod.getName().equals(methodExpression.getReferenceName())) continue; int index = indices.get(i); // we are in collections method implementation if (contextMethod != null && isInheritorOrSelf(contextMethod, patternMethod)) return null; final PsiClass calleeClass = calleeMethod.getContainingClass(); PsiSubstitutor substitutor = resolveResult.getSubstitutor(); final PsiClass patternClass = patternMethod.getContainingClass(); assert patternClass != null; assert calleeClass != null; substitutor = TypeConversionUtil.getClassSubstitutor(patternClass, calleeClass, substitutor); if (substitutor == null) continue; if (!patternMethod .getSignature(substitutor) .equals(calleeMethod.getSignature(PsiSubstitutor.EMPTY))) continue; PsiTypeParameter[] typeParameters = patternClass.getTypeParameters(); if (typeParameters.length <= index) return null; final PsiTypeParameter typeParameter = typeParameters[index]; PsiType typeParamMapping = substitutor.substitute(typeParameter); if (typeParamMapping == null) return null; PsiParameter[] parameters = patternMethod.getParameterList().getParameters(); if (parameters.length == 1 && "removeAll".equals(patternMethod.getName())) { PsiType paramType = parameters[0].getType(); if (InheritanceUtil.isInheritor(paramType, CommonClassNames.JAVA_UTIL_COLLECTION)) { PsiType qualifierType = qualifier.getType(); if (qualifierType != null) { final PsiType itemType = JavaGenericsUtil.getCollectionItemType(argType, calleeMethod.getResolveScope()); final PsiType qualifierItemType = JavaGenericsUtil.getCollectionItemType( qualifierType, calleeMethod.getResolveScope()); if (qualifierItemType != null && itemType != null && !qualifierItemType.isAssignableFrom(itemType)) { return InspectionsBundle.message( "inspection.suspicious.collections.method.calls.problem.descriptor", PsiFormatUtil.formatType(qualifierType, 0, PsiSubstitutor.EMPTY), PsiFormatUtil.formatType(itemType, 0, PsiSubstitutor.EMPTY)); } } return null; } } String message = null; if (typeParamMapping instanceof PsiCapturedWildcardType) { typeParamMapping = ((PsiCapturedWildcardType) typeParamMapping).getWildcard(); } if (!typeParamMapping.isAssignableFrom(argType)) { if (typeParamMapping.isConvertibleFrom(argType)) { if (reportConvertibleMethodCalls) { message = InspectionsBundle.message( "inspection.suspicious.collections.method.calls.problem.descriptor1", PsiFormatUtil.formatMethod( calleeMethod, substitutor, PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_CONTAINING_CLASS, PsiFormatUtilBase.SHOW_TYPE)); } } else { PsiType qualifierType = qualifier.getType(); if (qualifierType != null) { message = InspectionsBundle.message( "inspection.suspicious.collections.method.calls.problem.descriptor", PsiFormatUtil.formatType(qualifierType, 0, PsiSubstitutor.EMPTY), PsiFormatUtil.formatType(argType, 0, PsiSubstitutor.EMPTY)); } } } return message; } return null; }