void (@NotNull Project project, @NotNull PsiElement startElement, @NotNull ModPsiUpdater updater) { // smart psi pointer lost correct catch section when multiple catch sections were collapsed in batch mode, // so we need to re-calculate everything based on what exists at this point final PsiCatchSection catchSection = (PsiCatchSection)startElement; final PsiTryStatement tryStatement = (PsiTryStatement)catchSection.getParent(); final CatchSectionWrapper[] sections = CatchSectionWrapper.createWrappers(tryStatement); if (sections == null) return; int sectionIndex = getSectionIndex(sections, catchSection); if (sectionIndex < 0) return; CatchSectionWrapper duplicateSection = sections[sectionIndex]; if (duplicateSection == null) return; final boolean[][] canSwap = collectCanSwap(sections); final CatchSectionIndices[] duplicatesIndices = getCatchSectionIndices(sections, canSwap, myEmpty ? CatchSectionWrapper::areEmpty : (s1, s2) -> CatchSectionWrapper.areDuplicates( s1, s2, myIgnoreBlocksWithDifferentComments)); if (duplicatesIndices == null) return; final int collapseIntoIndex = duplicatesIndices[sectionIndex].myCollapseIntoIndex; if (collapseIntoIndex < 0) return; CatchSectionWrapper collapseIntoSection = sections[collapseIntoIndex]; if (collapseIntoSection == null) return; final PsiTypeElement collapseIntoTypeElement = collapseIntoSection.myParameter.getTypeElement(); if (collapseIntoTypeElement == null) return; final List<PsiType> parameterTypes = new ArrayList<>(collapseIntoSection.myTypes); parameterTypes.addAll(duplicateSection.myTypes); final List<PsiType> filteredTypes = PsiDisjunctionType.flattenAndRemoveDuplicates(parameterTypes); final PsiType disjunction = PsiDisjunctionType.createDisjunction(filteredTypes, tryStatement.getManager()); List<PsiClassType> targetTypes = CatchSectionWrapper.getClassTypes(disjunction); //try to choose catch block, which has target exception types. It helps to preserve names of variables and comments if (targetTypes != null && targetTypes.equals(duplicateSection.myTypes)) { CatchSectionWrapper temp = collapseIntoSection; collapseIntoSection = duplicateSection; duplicateSection = temp; } final Set<String> survivingCommentTexts = new HashSet<>(collectCommentTexts(collapseIntoSection.myCatchSection)); final PsiTypeElement newTypeElement = JavaPsiFacade.getElementFactory(project).createTypeElement(disjunction); final CommentTracker tracker = new CommentTracker(); JavaCodeStyleManager.getInstance(project).shortenClassReferences(tracker.replace(collapseIntoTypeElement, newTypeElement)); int insertBeforeIndex = duplicatesIndices[sectionIndex].myCanInsertBefore; if (collapseIntoIndex < insertBeforeIndex) { // We can't leave the merged 'catch' section at collapseIntoIndex because it conflicts with other caught exceptions final PsiCatchSection[] catchSections = tryStatement.getCatchSections(); if (insertBeforeIndex < catchSections.length && catchSections[insertBeforeIndex] != null) { CatchSectionWrapper finalCollapseIntoSection = collapseIntoSection; CodeStyleManager.getInstance(tryStatement.getProject()).performActionWithFormatterDisabled((Runnable)() -> { PsiCatchSection sectionToMove = finalCollapseIntoSection.myCatchSection; PsiElement toCopy = null; if (sectionToMove.getNextSibling() instanceof PsiWhiteSpace whiteSpace) { toCopy = whiteSpace.copy(); } PsiElement element = tryStatement.addBefore(finalCollapseIntoSection.myCatchSection, catchSections[insertBeforeIndex]); if (toCopy != null) { tryStatement.addAfter(toCopy, element); } if (sectionToMove.getNextSibling() instanceof PsiWhiteSpace psiWhiteSpace) { psiWhiteSpace.delete(); } sectionToMove.delete(); }); } } PsiTreeUtil.processElements(duplicateSection.myCatchSection, element -> { if (element instanceof PsiComment) { final String text = getCommentText((PsiComment)element); if (text.isEmpty() || survivingCommentTexts.contains(text)) { tracker.markUnchanged(element); } } return true; }); tracker.grabComments(duplicateSection.myCatchSection); tracker.insertCommentsBefore(duplicateSection.myCatchSection); CatchSectionWrapper finalDuplicateSection = duplicateSection; CodeStyleManager.getInstance(tryStatement.getProject()).performActionWithFormatterDisabled((Runnable)() -> { if (finalDuplicateSection.myCatchSection.getNextSibling() instanceof PsiWhiteSpace whiteSpace) { whiteSpace.delete(); } finalDuplicateSection.myCatchSection.delete(); }); }