CmdLineParser: Replace PrefixedOption with AutoAnnotation

This annotation implementation was not following the contract of
Annotation in at least a few ways:
 * hashCode and equals were not implemented properly[1]
 * null values are not allowed[2]

AutoAnnotation ensures that the implementation meets the contract, and
reduces boilerplate.

(Other Annotation implementations in this class will require further
untangling and are split into separate changes.)

[1] https://docs.oracle.com/javase/8/docs/api/java/lang/annotation/Annotation.html#hashCode--
[2] https://docs.oracle.com/javase/specs/jls/se8/html/jls-9.html#jls-9.7.1

Change-Id: If7b0ddc86f4acd238bf968ce84bfc96fdff09dbb
diff --git a/java/com/google/gerrit/util/cli/BUILD b/java/com/google/gerrit/util/cli/BUILD
index c94fc1d..b9b9bba 100644
--- a/java/com/google/gerrit/util/cli/BUILD
+++ b/java/com/google/gerrit/util/cli/BUILD
@@ -7,6 +7,7 @@
         "//java/com/google/gerrit/common:server",
         "//lib:args4j",
         "//lib:guava",
+        "//lib/auto:auto-value-annotations",
         "//lib/flogger:api",
         "//lib/guice",
         "//lib/guice:guice-assistedinject",
diff --git a/java/com/google/gerrit/util/cli/CmdLineParser.java b/java/com/google/gerrit/util/cli/CmdLineParser.java
index 771451f..73e8d16 100644
--- a/java/com/google/gerrit/util/cli/CmdLineParser.java
+++ b/java/com/google/gerrit/util/cli/CmdLineParser.java
@@ -36,7 +36,9 @@
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.gerrit.util.cli.Localizable.localizable;
+import static java.util.Objects.requireNonNull;
 
+import com.google.auto.value.AutoAnnotation;
 import com.google.common.base.Strings;
 import com.google.common.collect.ListMultimap;
 import com.google.common.collect.Lists;
@@ -421,79 +423,37 @@
     throw new CmdLineException(parser, localizable("invalid boolean \"%s=%s\""), name, value);
   }
 
-  private static class PrefixedOption implements Option {
-    private final String prefix;
-    private final Option o;
+  private static Option newPrefixedOption(String prefix, Option o) {
+    requireNonNull(prefix);
+    checkArgument(o.name().startsWith("-"), "Option name must start with '-': %s", o);
+    String[] aliases = Arrays.stream(o.aliases()).map(prefix::concat).toArray(String[]::new);
+    return newOption(
+        prefix + o.name(),
+        aliases,
+        o.usage(),
+        o.metaVar(),
+        o.required(),
+        false,
+        o.hidden(),
+        o.handler(),
+        o.depends(),
+        new String[0]);
+  }
 
-    PrefixedOption(String prefix, Option o) {
-      this.prefix = prefix;
-      checkArgument(o.name().startsWith("-"), "Option name must start with '-': %s", o);
-      this.o = o;
-    }
-
-    @Override
-    public String name() {
-      return getPrefixedName(prefix, o.name());
-    }
-
-    @Override
-    public String[] aliases() {
-      String[] prefixedAliases = new String[o.aliases().length];
-      for (int i = 0; i < prefixedAliases.length; i++) {
-        prefixedAliases[i] = getPrefixedName(prefix, o.aliases()[i]);
-      }
-      return prefixedAliases;
-    }
-
-    @Override
-    public String usage() {
-      return o.usage();
-    }
-
-    @Override
-    public String metaVar() {
-      return o.metaVar();
-    }
-
-    @Override
-    public boolean required() {
-      return o.required();
-    }
-
-    @Override
-    public boolean hidden() {
-      return o.hidden();
-    }
-
-    @SuppressWarnings("rawtypes")
-    @Override
-    public Class<? extends OptionHandler> handler() {
-      return o.handler();
-    }
-
-    @Override
-    public String[] depends() {
-      return o.depends();
-    }
-
-    @Override
-    public String[] forbids() {
-      return null;
-    }
-
-    @Override
-    public boolean help() {
-      return false;
-    }
-
-    @Override
-    public Class<? extends Annotation> annotationType() {
-      return o.annotationType();
-    }
-
-    private static String getPrefixedName(String prefix, String name) {
-      return prefix + name;
-    }
+  @AutoAnnotation
+  private static Option newOption(
+      String name,
+      String[] aliases,
+      String usage,
+      String metaVar,
+      boolean required,
+      boolean help,
+      boolean hidden,
+      Class<? extends OptionHandler> handler,
+      String[] depends,
+      String[] forbids) {
+    return new AutoAnnotation_CmdLineParser_newOption(
+        name, aliases, usage, metaVar, required, help, hidden, handler, depends, forbids);
   }
 
   public class MyParser extends org.kohsuke.args4j.CmdLineParser {
@@ -569,7 +529,7 @@
           Option o = m.getAnnotation(Option.class);
           if (o != null) {
             queueOption(
-                new PrefixedOption(prefix, o),
+                newPrefixedOption(prefix, o),
                 new MethodSetter(this, bean, m),
                 m.getAnnotation(RequiresOptions.class));
           }
@@ -578,7 +538,7 @@
           Option o = f.getAnnotation(Option.class);
           if (o != null) {
             queueOption(
-                new PrefixedOption(prefix, o),
+                newPrefixedOption(prefix, o),
                 Setters.create(f, bean),
                 f.getAnnotation(RequiresOptions.class));
           }