public static ErrorProneOptions processArgs(Iterable<String> args) {
    Preconditions.checkNotNull(args);
    ImmutableList.Builder<String> remainingArgs = ImmutableList.builder();

    /* By default, we throw an error when an unknown option is passed in, if for example you
     * try to disable a check that doesn't match any of the known checks.  This catches typos from
     * the command line.
     *
     * You can pass the IGNORE_UNKNOWN_CHECKS_FLAG to opt-out of that checking.  This allows you to
     * use command lines from different versions of error-prone interchangeably.
     */
    boolean patchLocationSet = false;
    boolean patchCheckSet = false;
    Builder builder = new Builder();
    for (String arg : args) {
      switch (arg) {
        case IGNORE_SUPPRESSION_ANNOTATIONS:
          builder.setIgnoreSuppressionAnnotations(true);
          break;
        case IGNORE_UNKNOWN_CHECKS_FLAG:
          builder.setIgnoreUnknownChecks(true);
          break;
        case DISABLE_WARNINGS_IN_GENERATED_CODE_FLAG:
          builder.setDisableWarningsInGeneratedCode(true);
          break;
        case ERRORS_AS_WARNINGS_FLAG:
          builder.setDropErrorsToWarnings(true);
          break;
        case SUGGESTIONS_AS_WARNINGS_FLAG:
          builder.setSuggestionsAsWarnings(true);
          break;
        case ENABLE_ALL_CHECKS:
          builder.setEnableAllChecksAsWarnings(true);
          break;
        case DISABLE_ALL_CHECKS:
          builder.setDisableAllChecks(true);
          break;
        case COMPILING_TEST_ONLY_CODE:
          builder.setTestOnlyTarget(true);
          break;
        case COMPILING_PUBLICLY_VISIBLE_CODE:
          builder.setPubliclyVisibleTarget(true);
          break;
        case DISABLE_ALL_WARNINGS:
          builder.setDisableAllWarnings(true);
          break;
        default:
          if (arg.startsWith(SEVERITY_PREFIX)) {
            builder.parseSeverity(arg);
          } else if (arg.startsWith(ErrorProneFlags.PREFIX)) {
            builder.parseFlag(arg);
          } else if (arg.startsWith(PATCH_OUTPUT_LOCATION)) {
            patchLocationSet = true;
            String remaining = arg.substring(PATCH_OUTPUT_LOCATION.length());
            if (remaining.equals("IN_PLACE")) {
              builder.patchingOptionsBuilder().inPlace(true);
            } else {
              if (remaining.isEmpty()) {
                throw new InvalidCommandLineOptionException("invalid flag: " + arg);
              }
              builder.patchingOptionsBuilder().baseDirectory(remaining);
            }
          } else if (arg.startsWith(PATCH_CHECKS_PREFIX)) {
            patchCheckSet = true;
            String remaining = arg.substring(PATCH_CHECKS_PREFIX.length());
            if (remaining.startsWith("refaster:")) {
              // Refaster rule, load from InputStream at file
              builder
                  .patchingOptionsBuilder()
                  .customRefactorer(
                      () -> {
                        String path = remaining.substring("refaster:".length());
                        try (InputStream in =
                                Files.newInputStream(FileSystems.getDefault().getPath(path));
                            ObjectInputStream ois = new ObjectInputStream(in)) {
                          return (CodeTransformer) ois.readObject();
                        } catch (IOException | ClassNotFoundException e) {
                          throw new RuntimeException("Can't load Refaster rule from " + path, e);
                        }
                      });
            } else {
              Iterable<String> checks =
                  Splitter.on(',').trimResults().omitEmptyStrings().split(remaining);
              builder.patchingOptionsBuilder().namedCheckers(ImmutableSet.copyOf(checks));
            }
          } else if (arg.startsWith(PATCH_IMPORT_ORDER_PREFIX)) {
            String remaining = arg.substring(PATCH_IMPORT_ORDER_PREFIX.length());
            ImportOrganizer importOrganizer = ImportOrderParser.getImportOrganizer(remaining);
            builder.patchingOptionsBuilder().importOrganizer(importOrganizer);
          } else if (arg.startsWith(EXCLUDED_PATHS_PREFIX)) {
            String pathRegex = arg.substring(EXCLUDED_PATHS_PREFIX.length());
            builder.setExcludedPattern(Pattern.compile(pathRegex));

          } else {
            if (arg.startsWith(PREFIX)) {
              throw new InvalidCommandLineOptionException("invalid flag: " + arg);
            }
            remainingArgs.add(arg);
          }
      }
    }

    if (patchCheckSet && !patchLocationSet) {
      throw new InvalidCommandLineOptionException(
          "-XepPatchLocation must be specified when -XepPatchChecks is");
    }

    return builder.build(remainingArgs.build());
  }
@Test
  public void throwsExceptionWithBadPatchArgs() {
    assertThrows(
        InvalidCommandLineOptionException.class,
        () ->
            ErrorProneOptions.processArgs(new String[] {"-XepPatchChecks:FooBar,MissingOverride"}));
  }