boolean (@NotNull Project project, @NotNull VarianceCandidate candidate, boolean isExtends) { @NotNull PsiMethod method = candidate.method; PsiCodeBlock methodBody = method.getBody(); if (methodBody == null) return false; PsiClassType newParameterType = suggestMethodParameterType(candidate, isExtends); PsiMethod methodCopy = DebugUtil .performPsiModification("Creating method copy", () -> createMethodCopy(project, candidate.method, candidate.methodParameterIndex, newParameterType)); PsiClass containingClass = candidate.method.getContainingClass(); PsiField field = findFieldAssignedFromMethodParameter(candidate.methodParameter, method); List<PsiElement> superMethodsCalls = new ArrayList<>(); // shouldn't error-check these because they're not generalized yet findSuperMethodCallsInside(methodCopy, candidate.superMethods, superMethodsCalls); // for same-named methods we have to copy the class because the specific method would not be resolved otherwise if (field == null && containingClass.findMethodsByName(candidate.method.getName()).length == 1) { // check body only to avoid messing with @Override annotations errors return errorChecks(methodCopy.getBody(), superMethodsCalls); } // not anonymous nor local if (containingClass.getQualifiedName() != null) { // field can be referenced from anywhere in the file PsiMethod methodCopyInClass = DebugUtil.performPsiModification("Creating class copy", () -> createClassCopy(project, field, containingClass, candidate.method, methodCopy, newParameterType)); Collection<PsiMethod> methodsToErrorCheck; // check all field usages in the file if (field != null) { PsiClass classCopy = methodCopyInClass.getContainingClass(); int fieldIndex = ArrayUtil.indexOf(containingClass.getFields(), field); if (fieldIndex == -1) return false; PsiField fieldCopy = classCopy.getFields()[fieldIndex]; Collection<PsiReference> refs = ReferencesSearch.search(fieldCopy, new LocalSearchScope(classCopy)).findAll(); Map<PsiMethod, List<PsiReference>> collect = refs.stream() // map null to "method" to filter it out later .collect(Collectors.groupingBy(ref -> ObjectUtils.notNull(PsiTreeUtil.getParentOfType(ref.getElement(), PsiMethod.class), method))); methodsToErrorCheck = ContainerUtil.filter(collect.keySet(), k->k != method); } else { methodsToErrorCheck = Collections.singletonList(methodCopyInClass); } for (PsiMethod psiMethodCopy : methodsToErrorCheck) { PsiCodeBlock body = psiMethodCopy.getBody(); if (body != null && !errorChecks(body, superMethodsCalls)) return false; } return true; } // for anon/local have to copy containing method PsiMethod containingMethod = PsiTreeUtil.getParentOfType(containingClass, PsiMethod.class); if (containingMethod != null) { PsiMethod containingMethodCopy = DebugUtil .performPsiModification("Creating method copy", () -> createMethodCopy(project, containingMethod, -1, newParameterType)); // find anon class in the copy int anonClassOffsetInContainingMethod = containingClass.getTextRange().getStartOffset() - containingMethod.getTextRange().getStartOffset(); PsiElement element = containingMethodCopy.findElementAt(anonClassOffsetInContainingMethod); PsiClass containingClassCopy = PsiTreeUtil.getParentOfType(element, containingClass.getClass(), false); PsiMethod newMethodCopy = containingClassCopy.getMethods()[ArrayUtil.indexOf(containingClass.getMethods(), candidate.method)]; PsiTypeElement paramTE = Objects.requireNonNull(newMethodCopy.getParameterList().getParameter(candidate.methodParameterIndex)).getTypeElement(); ReplaceWithQuestionTFix.replaceType(project, paramTE, newParameterType); findSuperMethodCallsInside(newMethodCopy, candidate.superMethods, superMethodsCalls); return errorChecks(newMethodCopy.getBody(), superMethodsCalls); } return false; }