static void checkWithImprovedCatchAnalysis(@NotNull PsiParameter parameter,
                                             @NotNull Collection<? extends PsiClassType> thrownInTryStatement,
                                             @NotNull PsiFile containingFile, @NotNull Consumer<? super HighlightInfo.Builder> errorSink) {
    PsiElement scope = parameter.getDeclarationScope();
    if (!(scope instanceof PsiCatchSection catchSection)) return;

    PsiCatchSection[] allCatchSections = catchSection.getTryStatement().getCatchSections();
    int idx = ArrayUtilRt.find(allCatchSections, catchSection);
    if (idx <= 0) return;

    Collection<PsiClassType> thrownTypes = new HashSet<>(thrownInTryStatement);
    PsiManager manager = containingFile.getManager();
    GlobalSearchScope parameterResolveScope = parameter.getResolveScope();
    thrownTypes.add(PsiType.getJavaLangError(manager, parameterResolveScope));
    thrownTypes.add(PsiType.getJavaLangRuntimeException(manager, parameterResolveScope));

    List<PsiTypeElement> parameterTypeElements = PsiUtil.getParameterTypeElements(parameter);
    boolean isMultiCatch = parameterTypeElements.size() > 1;
    for (PsiTypeElement catchTypeElement : parameterTypeElements) {
      PsiType catchType = catchTypeElement.getType();
      if (ExceptionUtil.isGeneralExceptionType(catchType)) continue;

      // collect exceptions caught by this type
      List<PsiClassType> caught = new ArrayList<>();
      for (PsiClassType t : thrownTypes) {
        if (catchType.isAssignableFrom(t) || t.isAssignableFrom(catchType)) {
          caught.add(t);
        }
      }
      if (caught.isEmpty()) continue;
      Collection<PsiClassType> caughtCopy = new HashSet<>(caught);

      // exclude all caught by previous catch sections
      for (int i = 0; i < idx; i++) {
        PsiParameter prevCatchParameter = allCatchSections[i].getParameter();
        if (prevCatchParameter == null) continue;
        for (PsiTypeElement prevCatchTypeElement : PsiUtil.getParameterTypeElements(prevCatchParameter)) {
          PsiType prevCatchType = prevCatchTypeElement.getType();
          caught.removeIf(prevCatchType::isAssignableFrom);
          if (caught.isEmpty()) break;
        }
      }

      // check & warn
      if (caught.isEmpty()) {
        String message = JavaErrorBundle.message("exception.already.caught.warn", formatTypes(caughtCopy), caughtCopy.size());
        HighlightInfo.Builder builder =
          HighlightInfo.newHighlightInfo(HighlightInfoType.WARNING).range(catchSection).descriptionAndTooltip(message);
        IntentionAction action = isMultiCatch ?
                                 getFixFactory().createDeleteMultiCatchFix(catchTypeElement) :
                                 getFixFactory().createDeleteCatchFix(parameter);
        builder.registerFix(action, null, null, null, null);
        errorSink.accept(builder);
      }
    }
  }
static void checkWithImprovedCatchAnalysis(@NotNull PsiParameter parameter,
                                             @NotNull Collection<? extends PsiClassType> thrownInTryStatement,
                                             @NotNull PsiFile containingFile, @NotNull Consumer<? super HighlightInfo.Builder> errorSink)