1 //===- OptTable.cpp - Option Table Implementation -------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "llvm/Option/OptTable.h"
10 #include "llvm/ADT/STLExtras.h"
11 #include "llvm/ADT/StringRef.h"
12 #include "llvm/Option/Arg.h"
13 #include "llvm/Option/ArgList.h"
14 #include "llvm/Option/OptSpecifier.h"
15 #include "llvm/Option/Option.h"
16 #include "llvm/Support/CommandLine.h" // for expandResponseFiles
17 #include "llvm/Support/Compiler.h"
18 #include "llvm/Support/ErrorHandling.h"
19 #include "llvm/Support/raw_ostream.h"
31 using namespace llvm::opt
;
36 // Ordering on Info. The ordering is *almost* case-insensitive lexicographic,
37 // with an exception. '\0' comes at the end of the alphabet instead of the
38 // beginning (thus options precede any other options which prefix them).
39 static int StrCmpOptionNameIgnoreCase(StringRef A
, StringRef B
) {
40 size_t MinSize
= std::min(A
.size(), B
.size());
41 if (int Res
= A
.substr(0, MinSize
).compare_insensitive(B
.substr(0, MinSize
)))
44 if (A
.size() == B
.size())
47 return (A
.size() == MinSize
) ? 1 /* A is a prefix of B. */
48 : -1 /* B is a prefix of A */;
52 static int StrCmpOptionName(StringRef A
, StringRef B
) {
53 if (int N
= StrCmpOptionNameIgnoreCase(A
, B
))
58 static inline bool operator<(const OptTable::Info
&A
, const OptTable::Info
&B
) {
62 if (int N
= StrCmpOptionName(A
.getName(), B
.getName()))
65 for (size_t I
= 0, K
= std::min(A
.Prefixes
.size(), B
.Prefixes
.size()); I
!= K
;
67 if (int N
= StrCmpOptionName(A
.Prefixes
[I
], B
.Prefixes
[I
]))
70 // Names are the same, check that classes are in order; exactly one
71 // should be joined, and it should succeed the other.
72 assert(((A
.Kind
== Option::JoinedClass
) ^ (B
.Kind
== Option::JoinedClass
)) &&
73 "Unexpected classes for options with same name.");
74 return B
.Kind
== Option::JoinedClass
;
78 // Support lower_bound between info and an option name.
79 static inline bool operator<(const OptTable::Info
&I
, StringRef Name
) {
80 return StrCmpOptionNameIgnoreCase(I
.getName(), Name
) < 0;
83 } // end namespace opt
84 } // end namespace llvm
86 OptSpecifier::OptSpecifier(const Option
*Opt
) : ID(Opt
->getID()) {}
88 OptTable::OptTable(ArrayRef
<Info
> OptionInfos
, bool IgnoreCase
)
89 : OptionInfos(OptionInfos
), IgnoreCase(IgnoreCase
) {
90 // Explicitly zero initialize the error to work around a bug in array
91 // value-initialization on MinGW with gcc 4.3.5.
93 // Find start of normal options.
94 for (unsigned i
= 0, e
= getNumOptions(); i
!= e
; ++i
) {
95 unsigned Kind
= getInfo(i
+ 1).Kind
;
96 if (Kind
== Option::InputClass
) {
97 assert(!InputOptionID
&& "Cannot have multiple input options!");
98 InputOptionID
= getInfo(i
+ 1).ID
;
99 } else if (Kind
== Option::UnknownClass
) {
100 assert(!UnknownOptionID
&& "Cannot have multiple unknown options!");
101 UnknownOptionID
= getInfo(i
+ 1).ID
;
102 } else if (Kind
!= Option::GroupClass
) {
103 FirstSearchableIndex
= i
;
107 assert(FirstSearchableIndex
!= 0 && "No searchable options?");
110 // Check that everything after the first searchable option is a
111 // regular option class.
112 for (unsigned i
= FirstSearchableIndex
, e
= getNumOptions(); i
!= e
; ++i
) {
113 Option::OptionClass Kind
= (Option::OptionClass
) getInfo(i
+ 1).Kind
;
114 assert((Kind
!= Option::InputClass
&& Kind
!= Option::UnknownClass
&&
115 Kind
!= Option::GroupClass
) &&
116 "Special options should be defined first!");
119 // Check that options are in order.
120 for (unsigned i
= FirstSearchableIndex
+ 1, e
= getNumOptions(); i
!= e
; ++i
){
121 if (!(getInfo(i
) < getInfo(i
+ 1))) {
123 getOption(i
+ 1).dump();
124 llvm_unreachable("Options are not in order!");
130 void OptTable::buildPrefixChars() {
131 assert(PrefixChars
.empty() && "rebuilding a non-empty prefix char");
133 // Build prefix chars.
134 for (const StringLiteral
&Prefix
: getPrefixesUnion()) {
135 for (char C
: Prefix
)
136 if (!is_contained(PrefixChars
, C
))
137 PrefixChars
.push_back(C
);
141 OptTable::~OptTable() = default;
143 const Option
OptTable::getOption(OptSpecifier Opt
) const {
144 unsigned id
= Opt
.getID();
146 return Option(nullptr, nullptr);
147 assert((unsigned) (id
- 1) < getNumOptions() && "Invalid ID.");
148 return Option(&getInfo(id
), this);
151 static bool isInput(const ArrayRef
<StringLiteral
> &Prefixes
, StringRef Arg
) {
154 for (const StringRef
&Prefix
: Prefixes
)
155 if (Arg
.startswith(Prefix
))
160 /// \returns Matched size. 0 means no match.
161 static unsigned matchOption(const OptTable::Info
*I
, StringRef Str
,
163 for (auto Prefix
: I
->Prefixes
) {
164 if (Str
.startswith(Prefix
)) {
165 StringRef Rest
= Str
.substr(Prefix
.size());
166 bool Matched
= IgnoreCase
? Rest
.starts_with_insensitive(I
->getName())
167 : Rest
.startswith(I
->getName());
169 return Prefix
.size() + StringRef(I
->getName()).size();
175 // Returns true if one of the Prefixes + In.Names matches Option
176 static bool optionMatches(const OptTable::Info
&In
, StringRef Option
) {
177 for (auto Prefix
: In
.Prefixes
)
178 if (Option
.endswith(In
.getName()))
179 if (Option
.slice(0, Option
.size() - In
.getName().size()) == Prefix
)
184 // This function is for flag value completion.
185 // Eg. When "-stdlib=" and "l" was passed to this function, it will return
186 // appropiriate values for stdlib, which starts with l.
187 std::vector
<std::string
>
188 OptTable::suggestValueCompletions(StringRef Option
, StringRef Arg
) const {
189 // Search all options and return possible values.
190 for (size_t I
= FirstSearchableIndex
, E
= OptionInfos
.size(); I
< E
; I
++) {
191 const Info
&In
= OptionInfos
[I
];
192 if (!In
.Values
|| !optionMatches(In
, Option
))
195 SmallVector
<StringRef
, 8> Candidates
;
196 StringRef(In
.Values
).split(Candidates
, ",", -1, false);
198 std::vector
<std::string
> Result
;
199 for (StringRef Val
: Candidates
)
200 if (Val
.startswith(Arg
) && Arg
.compare(Val
))
201 Result
.push_back(std::string(Val
));
207 std::vector
<std::string
>
208 OptTable::findByPrefix(StringRef Cur
, Visibility VisibilityMask
,
209 unsigned int DisableFlags
) const {
210 std::vector
<std::string
> Ret
;
211 for (size_t I
= FirstSearchableIndex
, E
= OptionInfos
.size(); I
< E
; I
++) {
212 const Info
&In
= OptionInfos
[I
];
213 if (In
.Prefixes
.empty() || (!In
.HelpText
&& !In
.GroupID
))
215 if (!(In
.Visibility
& VisibilityMask
))
217 if (In
.Flags
& DisableFlags
)
220 for (auto Prefix
: In
.Prefixes
) {
221 std::string S
= (Prefix
+ In
.getName() + "\t").str();
224 if (StringRef(S
).startswith(Cur
) && S
!= std::string(Cur
) + "\t")
231 unsigned OptTable::findNearest(StringRef Option
, std::string
&NearestString
,
232 Visibility VisibilityMask
,
233 unsigned MinimumLength
,
234 unsigned MaximumDistance
) const {
235 return internalFindNearest(
236 Option
, NearestString
, MinimumLength
, MaximumDistance
,
237 [VisibilityMask
](const Info
&CandidateInfo
) {
238 return (CandidateInfo
.Visibility
& VisibilityMask
) == 0;
242 unsigned OptTable::findNearest(StringRef Option
, std::string
&NearestString
,
243 unsigned FlagsToInclude
, unsigned FlagsToExclude
,
244 unsigned MinimumLength
,
245 unsigned MaximumDistance
) const {
246 return internalFindNearest(
247 Option
, NearestString
, MinimumLength
, MaximumDistance
,
248 [FlagsToInclude
, FlagsToExclude
](const Info
&CandidateInfo
) {
249 if (FlagsToInclude
&& !(CandidateInfo
.Flags
& FlagsToInclude
))
251 if (CandidateInfo
.Flags
& FlagsToExclude
)
257 unsigned OptTable::internalFindNearest(
258 StringRef Option
, std::string
&NearestString
, unsigned MinimumLength
,
259 unsigned MaximumDistance
,
260 std::function
<bool(const Info
&)> ExcludeOption
) const {
261 assert(!Option
.empty());
263 // Consider each [option prefix + option name] pair as a candidate, finding
264 // the closest match.
265 unsigned BestDistance
=
266 MaximumDistance
== UINT_MAX
? UINT_MAX
: MaximumDistance
+ 1;
267 SmallString
<16> Candidate
;
268 SmallString
<16> NormalizedName
;
270 for (const Info
&CandidateInfo
:
271 ArrayRef
<Info
>(OptionInfos
).drop_front(FirstSearchableIndex
)) {
272 StringRef CandidateName
= CandidateInfo
.getName();
274 // We can eliminate some option prefix/name pairs as candidates right away:
275 // * Ignore option candidates with empty names, such as "--", or names
276 // that do not meet the minimum length.
277 if (CandidateName
.size() < MinimumLength
)
280 // Ignore options that are excluded via masks
281 if (ExcludeOption(CandidateInfo
))
284 // * Ignore positional argument option candidates (which do not
286 if (CandidateInfo
.Prefixes
.empty())
289 // Now check if the candidate ends with a character commonly used when
290 // delimiting an option from its value, such as '=' or ':'. If it does,
291 // attempt to split the given option based on that delimiter.
292 char Last
= CandidateName
.back();
293 bool CandidateHasDelimiter
= Last
== '=' || Last
== ':';
295 if (CandidateHasDelimiter
) {
296 std::tie(NormalizedName
, RHS
) = Option
.split(Last
);
297 if (Option
.find(Last
) == NormalizedName
.size())
298 NormalizedName
+= Last
;
300 NormalizedName
= Option
;
302 // Consider each possible prefix for each candidate to find the most
303 // appropriate one. For example, if a user asks for "--helm", suggest
304 // "--help" over "-help".
305 for (auto CandidatePrefix
: CandidateInfo
.Prefixes
) {
306 // If Candidate and NormalizedName have more than 'BestDistance'
307 // characters of difference, no need to compute the edit distance, it's
308 // going to be greater than BestDistance. Don't bother computing Candidate
310 size_t CandidateSize
= CandidatePrefix
.size() + CandidateName
.size(),
311 NormalizedSize
= NormalizedName
.size();
312 size_t AbsDiff
= CandidateSize
> NormalizedSize
313 ? CandidateSize
- NormalizedSize
314 : NormalizedSize
- CandidateSize
;
315 if (AbsDiff
> BestDistance
) {
318 Candidate
= CandidatePrefix
;
319 Candidate
+= CandidateName
;
320 unsigned Distance
= StringRef(Candidate
).edit_distance(
321 NormalizedName
, /*AllowReplacements=*/true,
322 /*MaxEditDistance=*/BestDistance
);
323 if (RHS
.empty() && CandidateHasDelimiter
) {
324 // The Candidate ends with a = or : delimiter, but the option passed in
325 // didn't contain the delimiter (or doesn't have anything after it).
326 // In that case, penalize the correction: `-nodefaultlibs` is more
327 // likely to be a spello for `-nodefaultlib` than `-nodefaultlib:` even
328 // though both have an unmodified editing distance of 1, since the
329 // latter would need an argument.
332 if (Distance
< BestDistance
) {
333 BestDistance
= Distance
;
334 NearestString
= (Candidate
+ RHS
).str();
341 // Parse a single argument, return the new argument, and update Index. If
342 // GroupedShortOptions is true, -a matches "-abc" and the argument in Args will
343 // be updated to "-bc". This overload does not support VisibilityMask or case
344 // insensitive options.
345 std::unique_ptr
<Arg
> OptTable::parseOneArgGrouped(InputArgList
&Args
,
346 unsigned &Index
) const {
347 // Anything that doesn't start with PrefixesUnion is an input, as is '-'
349 const char *CStr
= Args
.getArgString(Index
);
351 if (isInput(getPrefixesUnion(), Str
))
352 return std::make_unique
<Arg
>(getOption(InputOptionID
), Str
, Index
++, CStr
);
354 const Info
*End
= OptionInfos
.data() + OptionInfos
.size();
355 StringRef Name
= Str
.ltrim(PrefixChars
);
357 std::lower_bound(OptionInfos
.data() + FirstSearchableIndex
, End
, Name
);
358 const Info
*Fallback
= nullptr;
359 unsigned Prev
= Index
;
361 // Search for the option which matches Str.
362 for (; Start
!= End
; ++Start
) {
363 unsigned ArgSize
= matchOption(Start
, Str
, IgnoreCase
);
367 Option
Opt(Start
, this);
368 if (std::unique_ptr
<Arg
> A
=
369 Opt
.accept(Args
, StringRef(Args
.getArgString(Index
), ArgSize
),
370 /*GroupedShortOption=*/false, Index
))
373 // If Opt is a Flag of length 2 (e.g. "-a"), we know it is a prefix of
374 // the current argument (e.g. "-abc"). Match it as a fallback if no longer
375 // option (e.g. "-ab") exists.
376 if (ArgSize
== 2 && Opt
.getKind() == Option::FlagClass
)
379 // Otherwise, see if the argument is missing.
384 Option
Opt(Fallback
, this);
385 // Check that the last option isn't a flag wrongly given an argument.
387 return std::make_unique
<Arg
>(getOption(UnknownOptionID
), Str
, Index
++,
390 if (std::unique_ptr
<Arg
> A
= Opt
.accept(
391 Args
, Str
.substr(0, 2), /*GroupedShortOption=*/true, Index
)) {
392 Args
.replaceArgString(Index
, Twine('-') + Str
.substr(2));
397 // In the case of an incorrect short option extract the character and move to
400 CStr
= Args
.MakeArgString(Str
.substr(0, 2));
401 Args
.replaceArgString(Index
, Twine('-') + Str
.substr(2));
402 return std::make_unique
<Arg
>(getOption(UnknownOptionID
), CStr
, Index
, CStr
);
405 return std::make_unique
<Arg
>(getOption(UnknownOptionID
), Str
, Index
++, CStr
);
408 std::unique_ptr
<Arg
> OptTable::ParseOneArg(const ArgList
&Args
, unsigned &Index
,
409 Visibility VisibilityMask
) const {
410 return internalParseOneArg(Args
, Index
, [VisibilityMask
](const Option
&Opt
) {
411 return !Opt
.hasVisibilityFlag(VisibilityMask
);
415 std::unique_ptr
<Arg
> OptTable::ParseOneArg(const ArgList
&Args
, unsigned &Index
,
416 unsigned FlagsToInclude
,
417 unsigned FlagsToExclude
) const {
418 return internalParseOneArg(
419 Args
, Index
, [FlagsToInclude
, FlagsToExclude
](const Option
&Opt
) {
420 if (FlagsToInclude
&& !Opt
.hasFlag(FlagsToInclude
))
422 if (Opt
.hasFlag(FlagsToExclude
))
428 std::unique_ptr
<Arg
> OptTable::internalParseOneArg(
429 const ArgList
&Args
, unsigned &Index
,
430 std::function
<bool(const Option
&)> ExcludeOption
) const {
431 unsigned Prev
= Index
;
432 StringRef Str
= Args
.getArgString(Index
);
434 // Anything that doesn't start with PrefixesUnion is an input, as is '-'
436 if (isInput(getPrefixesUnion(), Str
))
437 return std::make_unique
<Arg
>(getOption(InputOptionID
), Str
, Index
++,
440 const Info
*Start
= OptionInfos
.data() + FirstSearchableIndex
;
441 const Info
*End
= OptionInfos
.data() + OptionInfos
.size();
442 StringRef Name
= Str
.ltrim(PrefixChars
);
444 // Search for the first next option which could be a prefix.
445 Start
= std::lower_bound(Start
, End
, Name
);
447 // Options are stored in sorted order, with '\0' at the end of the
448 // alphabet. Since the only options which can accept a string must
449 // prefix it, we iteratively search for the next option which could
452 // FIXME: This is searching much more than necessary, but I am
453 // blanking on the simplest way to make it fast. We can solve this
454 // problem when we move to TableGen.
455 for (; Start
!= End
; ++Start
) {
456 unsigned ArgSize
= 0;
457 // Scan for first option which is a proper prefix.
458 for (; Start
!= End
; ++Start
)
459 if ((ArgSize
= matchOption(Start
, Str
, IgnoreCase
)))
464 Option
Opt(Start
, this);
466 if (ExcludeOption(Opt
))
469 // See if this option matches.
470 if (std::unique_ptr
<Arg
> A
=
471 Opt
.accept(Args
, StringRef(Args
.getArgString(Index
), ArgSize
),
472 /*GroupedShortOption=*/false, Index
))
475 // Otherwise, see if this argument was missing values.
480 // If we failed to find an option and this arg started with /, then it's
481 // probably an input path.
483 return std::make_unique
<Arg
>(getOption(InputOptionID
), Str
, Index
++,
486 return std::make_unique
<Arg
>(getOption(UnknownOptionID
), Str
, Index
++,
490 InputArgList
OptTable::ParseArgs(ArrayRef
<const char *> Args
,
491 unsigned &MissingArgIndex
,
492 unsigned &MissingArgCount
,
493 Visibility VisibilityMask
) const {
494 return internalParseArgs(
495 Args
, MissingArgIndex
, MissingArgCount
,
496 [VisibilityMask
](const Option
&Opt
) {
497 return !Opt
.hasVisibilityFlag(VisibilityMask
);
501 InputArgList
OptTable::ParseArgs(ArrayRef
<const char *> Args
,
502 unsigned &MissingArgIndex
,
503 unsigned &MissingArgCount
,
504 unsigned FlagsToInclude
,
505 unsigned FlagsToExclude
) const {
506 return internalParseArgs(
507 Args
, MissingArgIndex
, MissingArgCount
,
508 [FlagsToInclude
, FlagsToExclude
](const Option
&Opt
) {
509 if (FlagsToInclude
&& !Opt
.hasFlag(FlagsToInclude
))
511 if (Opt
.hasFlag(FlagsToExclude
))
517 InputArgList
OptTable::internalParseArgs(
518 ArrayRef
<const char *> ArgArr
, unsigned &MissingArgIndex
,
519 unsigned &MissingArgCount
,
520 std::function
<bool(const Option
&)> ExcludeOption
) const {
521 InputArgList
Args(ArgArr
.begin(), ArgArr
.end());
523 // FIXME: Handle '@' args (or at least error on them).
525 MissingArgIndex
= MissingArgCount
= 0;
526 unsigned Index
= 0, End
= ArgArr
.size();
527 while (Index
< End
) {
528 // Ingore nullptrs, they are response file's EOL markers
529 if (Args
.getArgString(Index
) == nullptr) {
533 // Ignore empty arguments (other things may still take them as arguments).
534 StringRef Str
= Args
.getArgString(Index
);
540 // In DashDashParsing mode, the first "--" stops option scanning and treats
541 // all subsequent arguments as positional.
542 if (DashDashParsing
&& Str
== "--") {
543 while (++Index
< End
) {
544 Args
.append(new Arg(getOption(InputOptionID
), Str
, Index
,
545 Args
.getArgString(Index
)));
550 unsigned Prev
= Index
;
551 std::unique_ptr
<Arg
> A
= GroupedShortOptions
552 ? parseOneArgGrouped(Args
, Index
)
553 : internalParseOneArg(Args
, Index
, ExcludeOption
);
554 assert((Index
> Prev
|| GroupedShortOptions
) &&
555 "Parser failed to consume argument.");
557 // Check for missing argument error.
559 assert(Index
>= End
&& "Unexpected parser error.");
560 assert(Index
- Prev
- 1 && "No missing arguments!");
561 MissingArgIndex
= Prev
;
562 MissingArgCount
= Index
- Prev
- 1;
566 Args
.append(A
.release());
572 InputArgList
OptTable::parseArgs(int Argc
, char *const *Argv
,
573 OptSpecifier Unknown
, StringSaver
&Saver
,
574 std::function
<void(StringRef
)> ErrorFn
) const {
575 SmallVector
<const char *, 0> NewArgv
;
576 // The environment variable specifies initial options which can be overridden
577 // by commnad line options.
578 cl::expandResponseFiles(Argc
, Argv
, EnvVar
, Saver
, NewArgv
);
581 opt::InputArgList Args
= ParseArgs(ArrayRef(NewArgv
), MAI
, MAC
);
583 ErrorFn((Twine(Args
.getArgString(MAI
)) + ": missing argument").str());
585 // For each unknwon option, call ErrorFn with a formatted error message. The
586 // message includes a suggested alternative option spelling if available.
588 for (const opt::Arg
*A
: Args
.filtered(Unknown
)) {
589 std::string Spelling
= A
->getAsString(Args
);
590 if (findNearest(Spelling
, Nearest
) > 1)
591 ErrorFn("unknown argument '" + Spelling
+ "'");
593 ErrorFn("unknown argument '" + Spelling
+ "', did you mean '" + Nearest
+
599 static std::string
getOptionHelpName(const OptTable
&Opts
, OptSpecifier Id
) {
600 const Option O
= Opts
.getOption(Id
);
601 std::string Name
= O
.getPrefixedName().str();
603 // Add metavar, if used.
604 switch (O
.getKind()) {
605 case Option::GroupClass
: case Option::InputClass
: case Option::UnknownClass
:
606 llvm_unreachable("Invalid option with help text.");
608 case Option::MultiArgClass
:
609 if (const char *MetaVarName
= Opts
.getOptionMetaVar(Id
)) {
610 // For MultiArgs, metavar is full list of all argument names.
615 // For MultiArgs<N>, if metavar not supplied, print <value> N times.
616 for (unsigned i
=0, e
=O
.getNumArgs(); i
< e
; ++i
) {
622 case Option::FlagClass
:
625 case Option::ValuesClass
:
628 case Option::SeparateClass
: case Option::JoinedOrSeparateClass
:
629 case Option::RemainingArgsClass
: case Option::RemainingArgsJoinedClass
:
632 case Option::JoinedClass
: case Option::CommaJoinedClass
:
633 case Option::JoinedAndSeparateClass
:
634 if (const char *MetaVarName
= Opts
.getOptionMetaVar(Id
))
651 static void PrintHelpOptionList(raw_ostream
&OS
, StringRef Title
,
652 std::vector
<OptionInfo
> &OptionHelp
) {
653 OS
<< Title
<< ":\n";
655 // Find the maximum option length.
656 unsigned OptionFieldWidth
= 0;
657 for (const OptionInfo
&Opt
: OptionHelp
) {
658 // Limit the amount of padding we are willing to give up for alignment.
659 unsigned Length
= Opt
.Name
.size();
661 OptionFieldWidth
= std::max(OptionFieldWidth
, Length
);
664 const unsigned InitialPad
= 2;
665 for (const OptionInfo
&Opt
: OptionHelp
) {
666 const std::string
&Option
= Opt
.Name
;
667 int Pad
= OptionFieldWidth
- int(Option
.size());
668 OS
.indent(InitialPad
) << Option
;
670 // Break on long option names.
673 Pad
= OptionFieldWidth
+ InitialPad
;
675 OS
.indent(Pad
+ 1) << Opt
.HelpText
<< '\n';
679 static const char *getOptionHelpGroup(const OptTable
&Opts
, OptSpecifier Id
) {
680 unsigned GroupID
= Opts
.getOptionGroupID(Id
);
682 // If not in a group, return the default help group.
686 // Abuse the help text of the option groups to store the "help group"
689 // FIXME: Split out option groups.
690 if (const char *GroupHelp
= Opts
.getOptionHelpText(GroupID
))
693 // Otherwise keep looking.
694 return getOptionHelpGroup(Opts
, GroupID
);
697 void OptTable::printHelp(raw_ostream
&OS
, const char *Usage
, const char *Title
,
698 bool ShowHidden
, bool ShowAllAliases
,
699 Visibility VisibilityMask
) const {
700 return internalPrintHelp(
701 OS
, Usage
, Title
, ShowHidden
, ShowAllAliases
,
702 [VisibilityMask
](const Info
&CandidateInfo
) -> bool {
703 return (CandidateInfo
.Visibility
& VisibilityMask
) == 0;
707 void OptTable::printHelp(raw_ostream
&OS
, const char *Usage
, const char *Title
,
708 unsigned FlagsToInclude
, unsigned FlagsToExclude
,
709 bool ShowAllAliases
) const {
710 bool ShowHidden
= !(FlagsToExclude
& HelpHidden
);
711 FlagsToExclude
&= ~HelpHidden
;
712 return internalPrintHelp(
713 OS
, Usage
, Title
, ShowHidden
, ShowAllAliases
,
714 [FlagsToInclude
, FlagsToExclude
](const Info
&CandidateInfo
) {
715 if (FlagsToInclude
&& !(CandidateInfo
.Flags
& FlagsToInclude
))
717 if (CandidateInfo
.Flags
& FlagsToExclude
)
723 void OptTable::internalPrintHelp(
724 raw_ostream
&OS
, const char *Usage
, const char *Title
, bool ShowHidden
,
726 std::function
<bool(const Info
&)> ExcludeOption
) const {
727 OS
<< "OVERVIEW: " << Title
<< "\n\n";
728 OS
<< "USAGE: " << Usage
<< "\n\n";
730 // Render help text into a map of group-name to a list of (option, help)
732 std::map
<std::string
, std::vector
<OptionInfo
>> GroupedOptionHelp
;
734 for (unsigned Id
= 1, e
= getNumOptions() + 1; Id
!= e
; ++Id
) {
735 // FIXME: Split out option groups.
736 if (getOptionKind(Id
) == Option::GroupClass
)
739 const Info
&CandidateInfo
= getInfo(Id
);
740 if (!ShowHidden
&& (CandidateInfo
.Flags
& opt::HelpHidden
))
743 if (ExcludeOption(CandidateInfo
))
746 // If an alias doesn't have a help text, show a help text for the aliased
748 const char *HelpText
= getOptionHelpText(Id
);
749 if (!HelpText
&& ShowAllAliases
) {
750 const Option Alias
= getOption(Id
).getAlias();
752 HelpText
= getOptionHelpText(Alias
.getID());
755 if (HelpText
&& (strlen(HelpText
) != 0)) {
756 const char *HelpGroup
= getOptionHelpGroup(*this, Id
);
757 const std::string
&OptName
= getOptionHelpName(*this, Id
);
758 GroupedOptionHelp
[HelpGroup
].push_back({OptName
, HelpText
});
762 for (auto& OptionGroup
: GroupedOptionHelp
) {
763 if (OptionGroup
.first
!= GroupedOptionHelp
.begin()->first
)
765 PrintHelpOptionList(OS
, OptionGroup
.first
, OptionGroup
.second
);
771 GenericOptTable::GenericOptTable(ArrayRef
<Info
> OptionInfos
, bool IgnoreCase
)
772 : OptTable(OptionInfos
, IgnoreCase
) {
774 std::set
<StringLiteral
> TmpPrefixesUnion
;
775 for (auto const &Info
: OptionInfos
.drop_front(FirstSearchableIndex
))
776 TmpPrefixesUnion
.insert(Info
.Prefixes
.begin(), Info
.Prefixes
.end());
777 PrefixesUnionBuffer
.append(TmpPrefixesUnion
.begin(), TmpPrefixesUnion
.end());