private static boolean tryStatementsAreEquivalent(
     @NotNull PsiTryStatement statement1, @NotNull PsiTryStatement statement2) {
   final PsiCodeBlock tryBlock1 = statement1.getTryBlock();
   final PsiCodeBlock tryBlock2 = statement2.getTryBlock();
   if (!codeBlocksAreEquivalent(tryBlock1, tryBlock2)) {
     return false;
   }
   final PsiCodeBlock finallyBlock1 = statement1.getFinallyBlock();
   final PsiCodeBlock finallyBlock2 = statement2.getFinallyBlock();
   if (!codeBlocksAreEquivalent(finallyBlock1, finallyBlock2)) {
     return false;
   }
   final PsiCodeBlock[] catchBlocks1 = statement1.getCatchBlocks();
   final PsiCodeBlock[] catchBlocks2 = statement2.getCatchBlocks();
   if (catchBlocks1.length != catchBlocks2.length) {
     return false;
   }
   for (int i = 0; i < catchBlocks2.length; i++) {
     if (!codeBlocksAreEquivalent(catchBlocks1[i], catchBlocks2[i])) {
       return false;
     }
   }
   final PsiParameter[] catchParameters1 = statement1.getCatchBlockParameters();
   final PsiParameter[] catchParameters2 = statement2.getCatchBlockParameters();
   if (catchParameters1.length != catchParameters2.length) {
     return false;
   }
   for (int i = 0; i < catchParameters2.length; i++) {
     if (!parametersAreEquivalent(catchParameters2[i], catchParameters1[i])) {
       return false;
     }
   }
   return true;
 }
 private static boolean tryStatementsAreEquivalent(
     @NotNull PsiTryStatement statement1, @NotNull PsiTryStatement statement2) {
   final PsiCodeBlock tryBlock1 = statement1.getTryBlock();
   final PsiCodeBlock tryBlock2 = statement2.getTryBlock();
   if (!codeBlocksAreEquivalent(tryBlock1, tryBlock2)) {
     return false;
   }
   final PsiCodeBlock finallyBlock1 = statement1.getFinallyBlock();
   final PsiCodeBlock finallyBlock2 = statement2.getFinallyBlock();
   if (!codeBlocksAreEquivalent(finallyBlock1, finallyBlock2)) {
     return false;
   }
   final PsiCodeBlock[] catchBlocks1 = statement1.getCatchBlocks();
   final PsiCodeBlock[] catchBlocks2 = statement2.getCatchBlocks();
   if (catchBlocks1.length != catchBlocks2.length) {
     return false;
   }
   for (int i = 0; i < catchBlocks2.length; i++) {
     if (!codeBlocksAreEquivalent(catchBlocks1[i], catchBlocks2[i])) {
       return false;
     }
   }
   final PsiResourceList resourceList1 = statement1.getResourceList();
   final PsiResourceList resourceList2 = statement2.getResourceList();
   if (resourceList1 != null) {
     if (resourceList2 == null) {
       return false;
     }
     if (resourceList1.getResourceVariablesCount() != resourceList2.getResourceVariablesCount()) {
       return false;
     }
     final List<PsiResourceVariable> resourceVariables1 = resourceList1.getResourceVariables();
     final List<PsiResourceVariable> resourceVariables2 = resourceList2.getResourceVariables();
     for (int i1 = 0, size = resourceVariables1.size(); i1 < size; i1++) {
       final PsiResourceVariable variable1 = resourceVariables1.get(i1);
       final PsiResourceVariable variable2 = resourceVariables2.get(i1);
       if (!localVariablesAreEquivalent(variable1, variable2)) {
         return false;
       }
     }
   } else if (resourceList2 != null) {
     return false;
   }
   final PsiParameter[] catchParameters1 = statement1.getCatchBlockParameters();
   final PsiParameter[] catchParameters2 = statement2.getCatchBlockParameters();
   if (catchParameters1.length != catchParameters2.length) {
     return false;
   }
   for (int i = 0; i < catchParameters2.length; i++) {
     if (!parametersAreEquivalent(catchParameters2[i], catchParameters1[i])) {
       return false;
     }
   }
   return true;
 }
  private static void fixExceptions(PsiElement ref, PsiClassType[] newExceptions)
      throws IncorrectOperationException {
    // methods' throws lists are already modified, may use ExceptionUtil.collectUnhandledExceptions
    newExceptions = filterCheckedExceptions(newExceptions);

    PsiElement context = PsiTreeUtil.getParentOfType(ref, PsiTryStatement.class, PsiMethod.class);
    if (context instanceof PsiTryStatement) {
      PsiTryStatement tryStatement = (PsiTryStatement) context;
      PsiCodeBlock tryBlock = tryStatement.getTryBlock();

      // Remove unused catches
      Collection<PsiClassType> classes =
          ExceptionUtil.collectUnhandledExceptions(tryBlock, tryBlock);
      PsiParameter[] catchParameters = tryStatement.getCatchBlockParameters();
      for (PsiParameter parameter : catchParameters) {
        final PsiType caughtType = parameter.getType();

        if (!(caughtType instanceof PsiClassType)) continue;
        if (ExceptionUtil.isUncheckedExceptionOrSuperclass((PsiClassType) caughtType)) continue;

        if (!isCatchParameterRedundant((PsiClassType) caughtType, classes)) continue;
        parameter.getParent().delete(); // delete catch section
      }

      PsiClassType[] exceptionsToAdd = filterUnhandledExceptions(newExceptions, tryBlock);
      addExceptions(exceptionsToAdd, tryStatement);

      adjustPossibleEmptyTryStatement(tryStatement);
    } else {
      newExceptions = filterUnhandledExceptions(newExceptions, ref);
      if (newExceptions.length > 0) {
        // Add new try statement
        PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(ref.getProject());
        PsiTryStatement tryStatement =
            (PsiTryStatement)
                elementFactory.createStatementFromText("try {} catch (Exception e) {}", null);
        PsiStatement anchor = PsiTreeUtil.getParentOfType(ref, PsiStatement.class);
        LOG.assertTrue(anchor != null);
        tryStatement.getTryBlock().add(anchor);
        tryStatement = (PsiTryStatement) anchor.getParent().addAfter(tryStatement, anchor);

        addExceptions(newExceptions, tryStatement);
        anchor.delete();
        tryStatement.getCatchSections()[0].delete(); // Delete dummy catch section
      }
    }
  }