blob: 301f2d49be4876486d91dd03114a3c03f6371ff1 [file] [log] [blame]
Damien Martin-Guillerezf88f4d82015-09-25 13:56:55 +00001// Copyright 2014 The Bazel Authors. All rights reserved.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package com.google.devtools.common.options;
16
17import com.google.common.base.Function;
18import com.google.common.base.Functions;
19import com.google.common.base.Joiner;
20import com.google.common.base.Preconditions;
21import com.google.common.collect.ImmutableList;
22import com.google.common.collect.Lists;
23import com.google.common.collect.Maps;
Ulf Adams352211d2016-06-22 09:24:28 +000024import com.google.common.escape.Escaper;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010025
26import java.lang.reflect.Field;
27import java.util.ArrayList;
28import java.util.Arrays;
29import java.util.Collection;
30import java.util.Collections;
Damien Martin-Guillerezfbed1062015-09-03 14:32:52 +000031import java.util.Comparator;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010032import java.util.List;
33import java.util.Map;
34
35/**
36 * A parser for options. Typical use case in a main method:
37 *
38 * <pre>
39 * OptionsParser parser = OptionsParser.newOptionsParser(FooOptions.class, BarOptions.class);
40 * parser.parseAndExitUponError(args);
41 * FooOptions foo = parser.getOptions(FooOptions.class);
42 * BarOptions bar = parser.getOptions(BarOptions.class);
43 * List&lt;String&gt; otherArguments = parser.getResidue();
44 * </pre>
45 *
46 * <p>FooOptions and BarOptions would be options specification classes, derived
47 * from OptionsBase, that contain fields annotated with @Option(...).
48 *
49 * <p>Alternatively, rather than calling
50 * {@link #parseAndExitUponError(OptionPriority, String, String[])},
51 * client code may call {@link #parse(OptionPriority,String,List)}, and handle
52 * parser exceptions usage messages themselves.
53 *
54 * <p>This options parsing implementation has (at least) one design flaw. It
55 * allows both '--foo=baz' and '--foo baz' for all options except void, boolean
56 * and tristate options. For these, the 'baz' in '--foo baz' is not treated as
57 * a parameter to the option, making it is impossible to switch options between
58 * void/boolean/tristate and everything else without breaking backwards
59 * compatibility.
60 *
61 * @see Options a simpler class which you can use if you only have one options
62 * specification class
63 */
64public class OptionsParser implements OptionsProvider {
65
66 /**
67 * A cache for the parsed options data. Both keys and values are immutable, so
68 * this is always safe. Only access this field through the {@link
69 * #getOptionsData} method for thread-safety! The cache is very unlikely to
70 * grow to a significant amount of memory, because there's only a fixed set of
71 * options classes on the classpath.
72 */
73 private static final Map<ImmutableList<Class<? extends OptionsBase>>, OptionsData> optionsData =
74 Maps.newHashMap();
75
Nathan Harmata19350de2016-04-29 21:44:30 +000076 /**
77 * Returns {@link OpaqueOptionsData} suitable for passing along to
78 * {@link #newOptionsParser(OpaqueOptionsData optionsData)}.
79 *
80 * This is useful when you want to do the work of analyzing the given {@code optionsClasses}
81 * exactly once, but you want to parse lots of different lists of strings (and thus need to
82 * construct lots of different {@link OptionsParser} instances).
83 */
84 public static OpaqueOptionsData getOptionsData(
85 ImmutableList<Class<? extends OptionsBase>> optionsClasses) {
86 return getOptionsDataInternal(optionsClasses);
87 }
88
89 private static synchronized OptionsData getOptionsDataInternal(
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010090 ImmutableList<Class<? extends OptionsBase>> optionsClasses) {
91 OptionsData result = optionsData.get(optionsClasses);
92 if (result == null) {
93 result = OptionsData.of(optionsClasses);
94 optionsData.put(optionsClasses, result);
95 }
96 return result;
97 }
98
99 /**
100 * Returns all the annotated fields for the given class, including inherited
101 * ones.
102 */
103 static Collection<Field> getAllAnnotatedFields(Class<? extends OptionsBase> optionsClass) {
Nathan Harmata19350de2016-04-29 21:44:30 +0000104 OptionsData data = getOptionsDataInternal(
105 ImmutableList.<Class<? extends OptionsBase>>of(optionsClass));
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100106 return data.getFieldsForClass(optionsClass);
107 }
108
109 /**
110 * @see #newOptionsParser(Iterable)
111 */
112 public static OptionsParser newOptionsParser(Class<? extends OptionsBase> class1) {
113 return newOptionsParser(ImmutableList.<Class<? extends OptionsBase>>of(class1));
114 }
115
116 /**
117 * @see #newOptionsParser(Iterable)
118 */
119 public static OptionsParser newOptionsParser(Class<? extends OptionsBase> class1,
120 Class<? extends OptionsBase> class2) {
121 return newOptionsParser(ImmutableList.of(class1, class2));
122 }
123
124 /**
125 * Create a new {@link OptionsParser}.
126 */
127 public static OptionsParser newOptionsParser(
Janak Ramakrishnanb92c0972016-03-23 16:47:13 +0000128 Iterable<? extends Class<? extends OptionsBase>> optionsClasses) {
Nathan Harmata19350de2016-04-29 21:44:30 +0000129 return newOptionsParser(
130 getOptionsDataInternal(ImmutableList.<Class<? extends OptionsBase>>copyOf(optionsClasses)));
131 }
132
133 /**
134 * Create a new {@link OptionsParser}, using {@link OpaqueOptionsData} previously returned from
135 * {@link #getOptionsData}.
136 */
137 public static OptionsParser newOptionsParser(OpaqueOptionsData optionsData) {
138 return new OptionsParser((OptionsData) optionsData);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100139 }
140
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100141 private final OptionsParserImpl impl;
142 private final List<String> residue = new ArrayList<String>();
143 private boolean allowResidue = true;
144
145 OptionsParser(Collection<Class<? extends OptionsBase>> optionsClasses) {
146 this(OptionsData.of(optionsClasses));
147 }
148
149 OptionsParser(OptionsData optionsData) {
150 impl = new OptionsParserImpl(optionsData);
151 }
152
153 /**
154 * Indicates whether or not the parser will allow a non-empty residue; that
155 * is, iff this value is true then a call to one of the {@code parse}
156 * methods will throw {@link OptionsParsingException} unless
157 * {@link #getResidue()} is empty after parsing.
158 */
159 public void setAllowResidue(boolean allowResidue) {
160 this.allowResidue = allowResidue;
161 }
162
163 /**
164 * Indicates whether or not the parser will allow long options with a
165 * single-dash, instead of the usual double-dash, too, eg. -example instead of just --example.
166 */
167 public void setAllowSingleDashLongOptions(boolean allowSingleDashLongOptions) {
168 this.impl.setAllowSingleDashLongOptions(allowSingleDashLongOptions);
169 }
170
171 public void parseAndExitUponError(String[] args) {
172 parseAndExitUponError(OptionPriority.COMMAND_LINE, "unknown", args);
173 }
174
175 /**
176 * A convenience function for use in main methods. Parses the command line
177 * parameters, and exits upon error. Also, prints out the usage message
178 * if "--help" appears anywhere within {@code args}.
179 */
180 public void parseAndExitUponError(OptionPriority priority, String source, String[] args) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100181 for (String arg : args) {
182 if (arg.equals("--help")) {
183 System.out.println(describeOptions(Collections.<String, String>emptyMap(),
184 HelpVerbosity.LONG));
185 System.exit(0);
186 }
187 }
Googlerf6a387c2016-02-24 22:45:32 +0000188 try {
189 parse(priority, source, Arrays.asList(args));
190 } catch (OptionsParsingException e) {
191 System.err.println("Error parsing command line: " + e.getMessage());
192 System.err.println("Try --help.");
193 System.exit(2);
194 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100195 }
196
197 /**
Alex Humesky2f3f4cf2015-09-29 01:42:00 +0000198 * The metadata about an option.
199 */
200 public static final class OptionDescription {
201
202 private final String name;
203 private final Object defaultValue;
204 private final Converter<?> converter;
205 private final boolean allowMultiple;
206
207 public OptionDescription(String name, Object defaultValue, Converter<?> converter,
208 boolean allowMultiple) {
209 this.name = name;
210 this.defaultValue = defaultValue;
211 this.converter = converter;
212 this.allowMultiple = allowMultiple;
213 }
214
215 public String getName() {
216 return name;
217 }
218
219 public Object getDefaultValue() {
220 return defaultValue;
221 }
222
223 public Converter<?> getConverter() {
224 return converter;
225 }
226
227 public boolean getAllowMultiple() {
228 return allowMultiple;
229 }
230 }
231
232 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100233 * The name and value of an option with additional metadata describing its
234 * priority, source, whether it was set via an implicit dependency, and if so,
235 * by which other option.
236 */
237 public static class OptionValueDescription {
238 private final String name;
239 private final Object value;
240 private final OptionPriority priority;
241 private final String source;
242 private final String implicitDependant;
243 private final String expandedFrom;
244
245 public OptionValueDescription(String name, Object value,
246 OptionPriority priority, String source, String implicitDependant, String expandedFrom) {
247 this.name = name;
248 this.value = value;
249 this.priority = priority;
250 this.source = source;
251 this.implicitDependant = implicitDependant;
252 this.expandedFrom = expandedFrom;
253 }
254
255 public String getName() {
256 return name;
257 }
258
259 public Object getValue() {
260 return value;
261 }
262
Alex Humesky2f3f4cf2015-09-29 01:42:00 +0000263 /**
264 * @return the priority of the thing that set this value for this flag
265 */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100266 public OptionPriority getPriority() {
267 return priority;
268 }
269
Alex Humesky2f3f4cf2015-09-29 01:42:00 +0000270 /**
271 * @return the thing that set this value for this flag
272 */
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100273 public String getSource() {
274 return source;
275 }
276
277 public String getImplicitDependant() {
278 return implicitDependant;
279 }
280
281 public boolean isImplicitDependency() {
282 return implicitDependant != null;
283 }
284
285 public String getExpansionParent() {
286 return expandedFrom;
287 }
288
289 public boolean isExpansion() {
290 return expandedFrom != null;
291 }
292
293 @Override
294 public String toString() {
295 StringBuilder result = new StringBuilder();
296 result.append("option '").append(name).append("' ");
297 result.append("set to '").append(value).append("' ");
298 result.append("with priority ").append(priority);
299 if (source != null) {
300 result.append(" and source '").append(source).append("'");
301 }
302 if (implicitDependant != null) {
303 result.append(" implicitly by ");
304 }
305 return result.toString();
306 }
307 }
308
309 /**
310 * The name and unparsed value of an option with additional metadata describing its
311 * priority, source, whether it was set via an implicit dependency, and if so,
312 * by which other option.
313 *
314 * <p>Note that the unparsed value and the source parameters can both be null.
315 */
316 public static class UnparsedOptionValueDescription {
317 private final String name;
318 private final Field field;
319 private final String unparsedValue;
320 private final OptionPriority priority;
321 private final String source;
322 private final boolean explicit;
323
324 public UnparsedOptionValueDescription(String name, Field field, String unparsedValue,
325 OptionPriority priority, String source, boolean explicit) {
326 this.name = name;
327 this.field = field;
328 this.unparsedValue = unparsedValue;
329 this.priority = priority;
330 this.source = source;
331 this.explicit = explicit;
332 }
333
334 public String getName() {
335 return name;
336 }
337
338 Field getField() {
339 return field;
340 }
341
342 public boolean isBooleanOption() {
343 return field.getType().equals(boolean.class);
344 }
345
346 private DocumentationLevel documentationLevel() {
347 Option option = field.getAnnotation(Option.class);
348 return OptionsParser.documentationLevel(option.category());
349 }
350
351 public boolean isDocumented() {
352 return documentationLevel() == DocumentationLevel.DOCUMENTED;
353 }
354
355 public boolean isHidden() {
356 return documentationLevel() == DocumentationLevel.HIDDEN;
357 }
358
359 boolean isExpansion() {
360 Option option = field.getAnnotation(Option.class);
361 return option.expansion().length > 0;
362 }
363
364 boolean isImplicitRequirement() {
365 Option option = field.getAnnotation(Option.class);
366 return option.implicitRequirements().length > 0;
367 }
368
369 boolean allowMultiple() {
370 Option option = field.getAnnotation(Option.class);
371 return option.allowMultiple();
372 }
373
374 public String getUnparsedValue() {
375 return unparsedValue;
376 }
377
378 OptionPriority getPriority() {
379 return priority;
380 }
381
382 public String getSource() {
383 return source;
384 }
385
386 public boolean isExplicit() {
387 return explicit;
388 }
389
390 @Override
391 public String toString() {
392 StringBuilder result = new StringBuilder();
393 result.append("option '").append(name).append("' ");
394 result.append("set to '").append(unparsedValue).append("' ");
395 result.append("with priority ").append(priority);
396 if (source != null) {
397 result.append(" and source '").append(source).append("'");
398 }
399 return result.toString();
400 }
401 }
402
403 /**
404 * The verbosity with which option help messages are displayed: short (just
405 * the name), medium (name, type, default, abbreviation), and long (full
406 * description).
407 */
408 public enum HelpVerbosity { LONG, MEDIUM, SHORT }
409
410 /**
411 * The level of documentation. Only documented options are output as part of
412 * the help.
413 *
414 * <p>We use 'hidden' so that options that form the protocol between the
415 * client and the server are not logged.
416 */
417 enum DocumentationLevel {
418 DOCUMENTED, UNDOCUMENTED, HIDDEN
419 }
420
421 /**
422 * Returns a description of all the options this parser can digest.
423 * In addition to {@link Option} annotations, this method also
424 * interprets {@link OptionsUsage} annotations which give an intuitive short
425 * description for the options.
426 *
427 * @param categoryDescriptions a mapping from category names to category
428 * descriptions. Options of the same category (see {@link
429 * Option#category}) will be grouped together, preceded by the description
430 * of the category.
431 * @param helpVerbosity if {@code long}, the options will be described
432 * verbosely, including their types, defaults and descriptions. If {@code
433 * medium}, the descriptions are omitted, and if {@code short}, the options
434 * are just enumerated.
435 */
436 public String describeOptions(Map<String, String> categoryDescriptions,
437 HelpVerbosity helpVerbosity) {
438 StringBuilder desc = new StringBuilder();
439 if (!impl.getOptionsClasses().isEmpty()) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100440 List<Field> allFields = Lists.newArrayList();
441 for (Class<? extends OptionsBase> optionsClass : impl.getOptionsClasses()) {
442 allFields.addAll(impl.getAnnotatedFieldsFor(optionsClass));
443 }
444 Collections.sort(allFields, OptionsUsage.BY_CATEGORY);
445 String prevCategory = null;
446
447 for (Field optionField : allFields) {
448 String category = optionField.getAnnotation(Option.class).category();
449 if (!category.equals(prevCategory)) {
450 prevCategory = category;
451 String description = categoryDescriptions.get(category);
452 if (description == null) {
453 description = "Options category '" + category + "'";
454 }
455 if (documentationLevel(category) == DocumentationLevel.DOCUMENTED) {
456 desc.append("\n").append(description).append(":\n");
457 }
458 }
459
460 if (documentationLevel(prevCategory) == DocumentationLevel.DOCUMENTED) {
461 OptionsUsage.getUsage(optionField, desc, helpVerbosity);
462 }
463 }
464 }
465 return desc.toString().trim();
466 }
467
468 /**
Ulf Adams352211d2016-06-22 09:24:28 +0000469 * Returns a description of all the options this parser can digest.
470 * In addition to {@link Option} annotations, this method also
471 * interprets {@link OptionsUsage} annotations which give an intuitive short
472 * description for the options.
473 *
474 * @param categoryDescriptions a mapping from category names to category
475 * descriptions. Options of the same category (see {@link
476 * Option#category}) will be grouped together, preceded by the description
477 * of the category.
478 */
479 public String describeOptionsHtml(Map<String, String> categoryDescriptions, Escaper escaper) {
480 StringBuilder desc = new StringBuilder();
481 if (!impl.getOptionsClasses().isEmpty()) {
482 List<Field> allFields = Lists.newArrayList();
483 for (Class<? extends OptionsBase> optionsClass : impl.getOptionsClasses()) {
484 allFields.addAll(impl.getAnnotatedFieldsFor(optionsClass));
485 }
486 Collections.sort(allFields, OptionsUsage.BY_CATEGORY);
487 String prevCategory = null;
488
489 for (Field optionField : allFields) {
490 String category = optionField.getAnnotation(Option.class).category();
491 DocumentationLevel level = documentationLevel(category);
492 if (!category.equals(prevCategory) && level == DocumentationLevel.DOCUMENTED) {
493 String description = categoryDescriptions.get(category);
494 if (description == null) {
495 description = "Options category '" + category + "'";
496 }
497 if (prevCategory != null) {
498 desc.append("</dl>\n\n");
499 }
500 desc.append(escaper.escape(description)).append(":\n");
501 desc.append("<dl>");
502 prevCategory = category;
503 }
504
505 if (level == DocumentationLevel.DOCUMENTED) {
506 OptionsUsage.getUsageHtml(optionField, desc, escaper);
507 }
508 }
509 desc.append("</dl>\n");
510 }
511 return desc.toString();
512 }
513
514 /**
Damien Martin-Guillerez29728d42015-04-09 20:48:04 +0000515 * Returns a string listing the possible flag completion for this command along with the command
516 * completion if any. See {@link OptionsUsage#getCompletion(Field, StringBuilder)} for more
517 * details on the format for the flag completion.
518 */
519 public String getOptionsCompletion() {
520 StringBuilder desc = new StringBuilder();
521
522 // List all options
523 List<Field> allFields = Lists.newArrayList();
524 for (Class<? extends OptionsBase> optionsClass : impl.getOptionsClasses()) {
525 allFields.addAll(impl.getAnnotatedFieldsFor(optionsClass));
526 }
Damien Martin-Guillerezfbed1062015-09-03 14:32:52 +0000527 // Sort field for deterministic ordering
528 Collections.sort(allFields, new Comparator<Field>() {
529 @Override
530 public int compare(Field f1, Field f2) {
531 String name1 = f1.getAnnotation(Option.class).name();
532 String name2 = f2.getAnnotation(Option.class).name();
533 return name1.compareTo(name2);
534 }
535 });
Damien Martin-Guillerez29728d42015-04-09 20:48:04 +0000536 for (Field optionField : allFields) {
537 String category = optionField.getAnnotation(Option.class).category();
538 if (documentationLevel(category) == DocumentationLevel.DOCUMENTED) {
539 OptionsUsage.getCompletion(optionField, desc);
540 }
541 }
542
543 return desc.toString();
544 }
545
546 /**
Alex Humesky2f3f4cf2015-09-29 01:42:00 +0000547 * Returns a description of the option.
548 *
549 * @return The {@link OptionValueDescription} for the option, or null if there is no option by
550 * the given name.
551 */
552 public OptionDescription getOptionDescription(String name) {
553 return impl.getOptionDescription(name);
554 }
555
556 /**
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100557 * Returns a description of the option value set by the last previous call to
558 * {@link #parse(OptionPriority, String, List)} that successfully set the given
559 * option. If the option is of type {@link List}, the description will
560 * correspond to any one of the calls, but not necessarily the last.
Alex Humesky2f3f4cf2015-09-29 01:42:00 +0000561 *
562 * @return The {@link OptionValueDescription} for the option, or null if the value has not been
563 * set.
564 * @throws IllegalArgumentException if there is no option by the given name.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100565 */
566 public OptionValueDescription getOptionValueDescription(String name) {
567 return impl.getOptionValueDescription(name);
568 }
569
570 static DocumentationLevel documentationLevel(String category) {
571 if ("undocumented".equals(category)) {
572 return DocumentationLevel.UNDOCUMENTED;
573 } else if ("hidden".equals(category)) {
574 return DocumentationLevel.HIDDEN;
575 } else {
576 return DocumentationLevel.DOCUMENTED;
577 }
578 }
579
580 /**
581 * A convenience method, equivalent to
582 * {@code parse(OptionPriority.COMMAND_LINE, null, Arrays.asList(args))}.
583 */
584 public void parse(String... args) throws OptionsParsingException {
585 parse(OptionPriority.COMMAND_LINE, (String) null, Arrays.asList(args));
586 }
587
588 /**
589 * A convenience method, equivalent to
590 * {@code parse(OptionPriority.COMMAND_LINE, null, args)}.
591 */
592 public void parse(List<String> args) throws OptionsParsingException {
593 parse(OptionPriority.COMMAND_LINE, (String) null, args);
594 }
595
596 /**
597 * Parses {@code args}, using the classes registered with this parser.
598 * {@link #getOptions(Class)} and {@link #getResidue()} return the results.
599 * May be called multiple times; later options override existing ones if they
600 * have equal or higher priority. The source of options is a free-form string
601 * that can be used for debugging. Strings that cannot be parsed as options
602 * accumulates as residue, if this parser allows it.
603 *
604 * @see OptionPriority
605 */
606 public void parse(OptionPriority priority, String source,
607 List<String> args) throws OptionsParsingException {
608 parseWithSourceFunction(priority, Functions.constant(source), args);
609 }
610
611 /**
612 * Parses {@code args}, using the classes registered with this parser.
613 * {@link #getOptions(Class)} and {@link #getResidue()} return the results. May be called
614 * multiple times; later options override existing ones if they have equal or higher priority.
615 * The source of options is given as a function that maps option names to the source of the
616 * option. Strings that cannot be parsed as options accumulates as* residue, if this parser
617 * allows it.
618 */
619 public void parseWithSourceFunction(OptionPriority priority,
620 Function<? super String, String> sourceFunction, List<String> args)
621 throws OptionsParsingException {
622 Preconditions.checkNotNull(priority);
623 Preconditions.checkArgument(priority != OptionPriority.DEFAULT);
624 residue.addAll(impl.parse(priority, sourceFunction, args));
625 if (!allowResidue && !residue.isEmpty()) {
626 String errorMsg = "Unrecognized arguments: " + Joiner.on(' ').join(residue);
627 throw new OptionsParsingException(errorMsg);
628 }
629 }
630
Alex Humesky2f3f4cf2015-09-29 01:42:00 +0000631 /**
632 * Clears the given option. Also clears expansion arguments and implicit requirements for that
633 * option.
634 *
635 * <p>This will not affect options objects that have already been retrieved from this parser
636 * through {@link #getOptions(Class)}.
637 *
638 * @param optionName The full name of the option to clear.
639 * @return A map of an option name to the old value of the options that were cleared.
640 * @throws IllegalArgumentException If the flag does not exist.
641 */
Alex Humesky92a3a812016-05-09 19:07:56 +0000642 public Map<String, OptionValueDescription> clearValue(String optionName)
643 throws OptionsParsingException {
Alex Humesky2f3f4cf2015-09-29 01:42:00 +0000644 Map<String, OptionValueDescription> clearedValues = Maps.newHashMap();
645 impl.clearValue(optionName, clearedValues);
646 return clearedValues;
647 }
648
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100649 @Override
650 public List<String> getResidue() {
651 return ImmutableList.copyOf(residue);
652 }
653
654 /**
655 * Returns a list of warnings about problems encountered by previous parse calls.
656 */
657 public List<String> getWarnings() {
658 return impl.getWarnings();
659 }
660
661 @Override
662 public <O extends OptionsBase> O getOptions(Class<O> optionsClass) {
663 return impl.getParsedOptions(optionsClass);
664 }
665
666 @Override
667 public boolean containsExplicitOption(String name) {
668 return impl.containsExplicitOption(name);
669 }
670
671 @Override
672 public List<UnparsedOptionValueDescription> asListOfUnparsedOptions() {
673 return impl.asListOfUnparsedOptions();
674 }
675
676 @Override
677 public List<UnparsedOptionValueDescription> asListOfExplicitOptions() {
678 return impl.asListOfExplicitOptions();
679 }
680
681 @Override
682 public List<OptionValueDescription> asListOfEffectiveOptions() {
683 return impl.asListOfEffectiveOptions();
684 }
Alex Humeskyc5ac4302016-01-15 19:21:03 +0000685
686 @Override
687 public List<String> canonicalize() {
688 return impl.asCanonicalizedList();
689 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100690}