docs: public static Optional<Fix> tryFailToAssertThrows(
        TryTree tryTree,
        List<? extends StatementTree> throwingStatements,
        Optional<Tree> failureMessage,
        VisitorState state) {
      List<? extends CatchTree> catchTrees = tryTree.getCatches();
      if (catchTrees.size() != 1) {
        return Optional.empty();
      }
      CatchTree catchTree = Iterables.getOnlyElement(catchTrees);
      SuggestedFix.Builder fix = SuggestedFix.builder();
      StringBuilder fixPrefix = new StringBuilder();
      if (throwingStatements.isEmpty()) {
        return Optional.empty();
      }
      List<? extends StatementTree> catchStatements = catchTree.getBlock().getStatements();
      fix.addStaticImport("org.junit.Assert.assertThrows");
      if (!catchStatements.isEmpty()) {
        // TODO(cushon): pick a fresh name for the variable, if necessary
        fixPrefix.append(String.format("%s = ", state.getSourceForNode(catchTree.getParameter())));
      }
      fixPrefix.append(
          String.format(
              "assertThrows(%s%s.class, () -> ",
              failureMessage
                  // Supplying a constant string adds little value, since a failure here always means
                  // the same thing: the method just called wasn't expected to complete normally, but
                  // it did.
                  .filter(t -> ASTHelpers.constValue(t, String.class) == null)
                  .map(t -> state.getSourceForNode(t) + ", ")
                  .orElse(""),
              state.getSourceForNode(catchTree.getParameter().getType())));
      boolean useExpressionLambda =
          throwingStatements.size() == 1
              && getOnlyElement(throwingStatements).getKind() == Kind.EXPRESSION_STATEMENT;
      if (!useExpressionLambda) {
        fixPrefix.append("{");
      }
      fix.replace(
          ((JCTree) tryTree).getStartPosition(),
          ((JCTree) throwingStatements.iterator().next()).getStartPosition(),
          fixPrefix.toString());
      if (useExpressionLambda) {
        fix.postfixWith(
            ((ExpressionStatementTree) throwingStatements.iterator().next()).getExpression(), ")");
      } else {
        fix.postfixWith(getLast(throwingStatements), "});");
      }
      if (catchStatements.isEmpty()) {
        fix.replace(
            state.getEndPosition(getLast(throwingStatements)), state.getEndPosition(tryTree), "");
      } else {
        fix.replace(
            /* startPos= */ state.getEndPosition(getLast(throwingStatements)),
            /* endPos= */ ((JCTree) catchStatements.get(0)).getStartPosition(),
            "\n");
        fix.replace(
            state.getEndPosition(getLast(catchStatements)), state.getEndPosition(tryTree), "");
      }
      return Optional.of(fix.build());
    }