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/OptionStrCmp.h"
20 #include "llvm/Support/raw_ostream.h"
32 using namespace llvm::opt
;
37 ArrayRef
<unsigned> PrefixesTable
;
39 explicit OptNameLess(const char *StrTable
, ArrayRef
<unsigned> PrefixesTable
)
40 : StrTable(StrTable
), PrefixesTable(PrefixesTable
) {}
43 inline bool operator()(const OptTable::Info
&A
,
44 const OptTable::Info
&B
) const {
48 if (int Cmp
= StrCmpOptionName(A
.getName(StrTable
, PrefixesTable
),
49 B
.getName(StrTable
, PrefixesTable
)))
52 SmallVector
<StringRef
, 8> APrefixes
, BPrefixes
;
53 A
.appendPrefixes(StrTable
, PrefixesTable
, APrefixes
);
54 B
.appendPrefixes(StrTable
, PrefixesTable
, BPrefixes
);
56 if (int Cmp
= StrCmpOptionPrefixes(APrefixes
, BPrefixes
))
59 // Names are the same, check that classes are in order; exactly one
60 // should be joined, and it should succeed the other.
62 ((A
.Kind
== Option::JoinedClass
) ^ (B
.Kind
== Option::JoinedClass
)) &&
63 "Unexpected classes for options with same name.");
64 return B
.Kind
== Option::JoinedClass
;
68 // Support lower_bound between info and an option name.
69 inline bool operator()(const OptTable::Info
&I
, StringRef Name
) const {
70 // Do not fallback to case sensitive comparison.
71 return StrCmpOptionName(I
.getName(StrTable
, PrefixesTable
), Name
, false) <
77 OptSpecifier::OptSpecifier(const Option
*Opt
) : ID(Opt
->getID()) {}
79 OptTable::OptTable(const char *StrTable
, ArrayRef
<unsigned> PrefixesTable
,
80 ArrayRef
<Info
> OptionInfos
, bool IgnoreCase
)
81 : StrTable(StrTable
), PrefixesTable(PrefixesTable
),
82 OptionInfos(OptionInfos
), IgnoreCase(IgnoreCase
) {
83 // Explicitly zero initialize the error to work around a bug in array
84 // value-initialization on MinGW with gcc 4.3.5.
86 // Find start of normal options.
87 for (unsigned i
= 0, e
= getNumOptions(); i
!= e
; ++i
) {
88 unsigned Kind
= getInfo(i
+ 1).Kind
;
89 if (Kind
== Option::InputClass
) {
90 assert(!InputOptionID
&& "Cannot have multiple input options!");
91 InputOptionID
= getInfo(i
+ 1).ID
;
92 } else if (Kind
== Option::UnknownClass
) {
93 assert(!UnknownOptionID
&& "Cannot have multiple unknown options!");
94 UnknownOptionID
= getInfo(i
+ 1).ID
;
95 } else if (Kind
!= Option::GroupClass
) {
96 FirstSearchableIndex
= i
;
100 assert(FirstSearchableIndex
!= 0 && "No searchable options?");
103 // Check that everything after the first searchable option is a
104 // regular option class.
105 for (unsigned i
= FirstSearchableIndex
, e
= getNumOptions(); i
!= e
; ++i
) {
106 Option::OptionClass Kind
= (Option::OptionClass
) getInfo(i
+ 1).Kind
;
107 assert((Kind
!= Option::InputClass
&& Kind
!= Option::UnknownClass
&&
108 Kind
!= Option::GroupClass
) &&
109 "Special options should be defined first!");
112 // Check that options are in order.
113 for (unsigned i
= FirstSearchableIndex
+ 1, e
= getNumOptions(); i
!= e
; ++i
){
114 if (!(OptNameLess(StrTable
, PrefixesTable
)(getInfo(i
), getInfo(i
+ 1)))) {
116 getOption(i
+ 1).dump();
117 llvm_unreachable("Options are not in order!");
123 void OptTable::buildPrefixChars() {
124 assert(PrefixChars
.empty() && "rebuilding a non-empty prefix char");
126 // Build prefix chars.
127 for (StringRef Prefix
: PrefixesUnion
) {
128 for (char C
: Prefix
)
129 if (!is_contained(PrefixChars
, C
))
130 PrefixChars
.push_back(C
);
134 OptTable::~OptTable() = default;
136 const Option
OptTable::getOption(OptSpecifier Opt
) const {
137 unsigned id
= Opt
.getID();
139 return Option(nullptr, nullptr);
140 assert((unsigned) (id
- 1) < getNumOptions() && "Invalid ID.");
141 return Option(&getInfo(id
), this);
144 static bool isInput(const ArrayRef
<StringRef
> &Prefixes
, StringRef Arg
) {
147 for (const StringRef
&Prefix
: Prefixes
)
148 if (Arg
.starts_with(Prefix
))
153 /// \returns Matched size. 0 means no match.
154 static unsigned matchOption(const char *StrTable
,
155 ArrayRef
<unsigned> PrefixesTable
,
156 const OptTable::Info
*I
, StringRef Str
,
158 StringRef Name
= I
->getName(StrTable
, PrefixesTable
);
159 for (unsigned PrefixOffset
: I
->getPrefixOffsets(PrefixesTable
)) {
160 StringRef Prefix
= &StrTable
[PrefixOffset
];
161 if (Str
.starts_with(Prefix
)) {
162 StringRef Rest
= Str
.substr(Prefix
.size());
163 bool Matched
= IgnoreCase
? Rest
.starts_with_insensitive(Name
)
164 : Rest
.starts_with(Name
);
166 return Prefix
.size() + Name
.size();
172 // Returns true if one of the Prefixes + In.Names matches Option
173 static bool optionMatches(const char *StrTable
,
174 ArrayRef
<unsigned> PrefixesTable
,
175 const OptTable::Info
&In
, StringRef Option
) {
176 StringRef Name
= In
.getName(StrTable
, PrefixesTable
);
177 if (Option
.consume_back(Name
))
178 for (unsigned PrefixOffset
: In
.getPrefixOffsets(PrefixesTable
))
179 if (Option
== &StrTable
[PrefixOffset
])
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(StrTable
, PrefixesTable
, 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
.starts_with(Arg
) && Arg
!= 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
.hasNoPrefix() || (!In
.HelpText
&& !In
.GroupID
))
215 if (!(In
.Visibility
& VisibilityMask
))
217 if (In
.Flags
& DisableFlags
)
220 StringRef Name
= In
.getName(StrTable
, PrefixesTable
);
221 for (unsigned PrefixOffset
: In
.getPrefixOffsets(PrefixesTable
)) {
222 StringRef Prefix
= &StrTable
[PrefixOffset
];
223 std::string S
= (Twine(Prefix
) + Name
+ "\t").str();
226 if (StringRef(S
).starts_with(Cur
) && S
!= std::string(Cur
) + "\t")
233 unsigned OptTable::findNearest(StringRef Option
, std::string
&NearestString
,
234 Visibility VisibilityMask
,
235 unsigned MinimumLength
,
236 unsigned MaximumDistance
) const {
237 return internalFindNearest(
238 Option
, NearestString
, MinimumLength
, MaximumDistance
,
239 [VisibilityMask
](const Info
&CandidateInfo
) {
240 return (CandidateInfo
.Visibility
& VisibilityMask
) == 0;
244 unsigned OptTable::findNearest(StringRef Option
, std::string
&NearestString
,
245 unsigned FlagsToInclude
, unsigned FlagsToExclude
,
246 unsigned MinimumLength
,
247 unsigned MaximumDistance
) const {
248 return internalFindNearest(
249 Option
, NearestString
, MinimumLength
, MaximumDistance
,
250 [FlagsToInclude
, FlagsToExclude
](const Info
&CandidateInfo
) {
251 if (FlagsToInclude
&& !(CandidateInfo
.Flags
& FlagsToInclude
))
253 if (CandidateInfo
.Flags
& FlagsToExclude
)
259 unsigned OptTable::internalFindNearest(
260 StringRef Option
, std::string
&NearestString
, unsigned MinimumLength
,
261 unsigned MaximumDistance
,
262 std::function
<bool(const Info
&)> ExcludeOption
) const {
263 assert(!Option
.empty());
265 // Consider each [option prefix + option name] pair as a candidate, finding
266 // the closest match.
267 unsigned BestDistance
=
268 MaximumDistance
== UINT_MAX
? UINT_MAX
: MaximumDistance
+ 1;
269 SmallString
<16> Candidate
;
270 SmallString
<16> NormalizedName
;
272 for (const Info
&CandidateInfo
:
273 ArrayRef
<Info
>(OptionInfos
).drop_front(FirstSearchableIndex
)) {
274 StringRef CandidateName
= CandidateInfo
.getName(StrTable
, PrefixesTable
);
276 // We can eliminate some option prefix/name pairs as candidates right away:
277 // * Ignore option candidates with empty names, such as "--", or names
278 // that do not meet the minimum length.
279 if (CandidateName
.size() < MinimumLength
)
282 // Ignore options that are excluded via masks
283 if (ExcludeOption(CandidateInfo
))
286 // * Ignore positional argument option candidates (which do not
288 if (CandidateInfo
.hasNoPrefix())
291 // Now check if the candidate ends with a character commonly used when
292 // delimiting an option from its value, such as '=' or ':'. If it does,
293 // attempt to split the given option based on that delimiter.
294 char Last
= CandidateName
.back();
295 bool CandidateHasDelimiter
= Last
== '=' || Last
== ':';
297 if (CandidateHasDelimiter
) {
298 std::tie(NormalizedName
, RHS
) = Option
.split(Last
);
299 if (Option
.find(Last
) == NormalizedName
.size())
300 NormalizedName
+= Last
;
302 NormalizedName
= Option
;
304 // Consider each possible prefix for each candidate to find the most
305 // appropriate one. For example, if a user asks for "--helm", suggest
306 // "--help" over "-help".
307 for (unsigned CandidatePrefixOffset
:
308 CandidateInfo
.getPrefixOffsets(PrefixesTable
)) {
309 StringRef CandidatePrefix
= &StrTable
[CandidatePrefixOffset
];
310 // If Candidate and NormalizedName have more than 'BestDistance'
311 // characters of difference, no need to compute the edit distance, it's
312 // going to be greater than BestDistance. Don't bother computing Candidate
314 size_t CandidateSize
= CandidatePrefix
.size() + CandidateName
.size(),
315 NormalizedSize
= NormalizedName
.size();
316 size_t AbsDiff
= CandidateSize
> NormalizedSize
317 ? CandidateSize
- NormalizedSize
318 : NormalizedSize
- CandidateSize
;
319 if (AbsDiff
> BestDistance
) {
322 Candidate
= CandidatePrefix
;
323 Candidate
+= CandidateName
;
324 unsigned Distance
= StringRef(Candidate
).edit_distance(
325 NormalizedName
, /*AllowReplacements=*/true,
326 /*MaxEditDistance=*/BestDistance
);
327 if (RHS
.empty() && CandidateHasDelimiter
) {
328 // The Candidate ends with a = or : delimiter, but the option passed in
329 // didn't contain the delimiter (or doesn't have anything after it).
330 // In that case, penalize the correction: `-nodefaultlibs` is more
331 // likely to be a spello for `-nodefaultlib` than `-nodefaultlib:` even
332 // though both have an unmodified editing distance of 1, since the
333 // latter would need an argument.
336 if (Distance
< BestDistance
) {
337 BestDistance
= Distance
;
338 NearestString
= (Candidate
+ RHS
).str();
345 // Parse a single argument, return the new argument, and update Index. If
346 // GroupedShortOptions is true, -a matches "-abc" and the argument in Args will
347 // be updated to "-bc". This overload does not support VisibilityMask or case
348 // insensitive options.
349 std::unique_ptr
<Arg
> OptTable::parseOneArgGrouped(InputArgList
&Args
,
350 unsigned &Index
) const {
351 // Anything that doesn't start with PrefixesUnion is an input, as is '-'
353 const char *CStr
= Args
.getArgString(Index
);
355 if (isInput(PrefixesUnion
, Str
))
356 return std::make_unique
<Arg
>(getOption(InputOptionID
), Str
, Index
++, CStr
);
358 const Info
*End
= OptionInfos
.data() + OptionInfos
.size();
359 StringRef Name
= Str
.ltrim(PrefixChars
);
361 std::lower_bound(OptionInfos
.data() + FirstSearchableIndex
, End
, Name
,
362 OptNameLess(StrTable
, PrefixesTable
));
363 const Info
*Fallback
= nullptr;
364 unsigned Prev
= Index
;
366 // Search for the option which matches Str.
367 for (; Start
!= End
; ++Start
) {
369 matchOption(StrTable
, PrefixesTable
, Start
, Str
, IgnoreCase
);
373 Option
Opt(Start
, this);
374 if (std::unique_ptr
<Arg
> A
=
375 Opt
.accept(Args
, StringRef(Args
.getArgString(Index
), ArgSize
),
376 /*GroupedShortOption=*/false, Index
))
379 // If Opt is a Flag of length 2 (e.g. "-a"), we know it is a prefix of
380 // the current argument (e.g. "-abc"). Match it as a fallback if no longer
381 // option (e.g. "-ab") exists.
382 if (ArgSize
== 2 && Opt
.getKind() == Option::FlagClass
)
385 // Otherwise, see if the argument is missing.
390 Option
Opt(Fallback
, this);
391 // Check that the last option isn't a flag wrongly given an argument.
393 return std::make_unique
<Arg
>(getOption(UnknownOptionID
), Str
, Index
++,
396 if (std::unique_ptr
<Arg
> A
= Opt
.accept(
397 Args
, Str
.substr(0, 2), /*GroupedShortOption=*/true, Index
)) {
398 Args
.replaceArgString(Index
, Twine('-') + Str
.substr(2));
403 // In the case of an incorrect short option extract the character and move to
406 CStr
= Args
.MakeArgString(Str
.substr(0, 2));
407 Args
.replaceArgString(Index
, Twine('-') + Str
.substr(2));
408 return std::make_unique
<Arg
>(getOption(UnknownOptionID
), CStr
, Index
, CStr
);
411 return std::make_unique
<Arg
>(getOption(UnknownOptionID
), Str
, Index
++, CStr
);
414 std::unique_ptr
<Arg
> OptTable::ParseOneArg(const ArgList
&Args
, unsigned &Index
,
415 Visibility VisibilityMask
) const {
416 return internalParseOneArg(Args
, Index
, [VisibilityMask
](const Option
&Opt
) {
417 return !Opt
.hasVisibilityFlag(VisibilityMask
);
421 std::unique_ptr
<Arg
> OptTable::ParseOneArg(const ArgList
&Args
, unsigned &Index
,
422 unsigned FlagsToInclude
,
423 unsigned FlagsToExclude
) const {
424 return internalParseOneArg(
425 Args
, Index
, [FlagsToInclude
, FlagsToExclude
](const Option
&Opt
) {
426 if (FlagsToInclude
&& !Opt
.hasFlag(FlagsToInclude
))
428 if (Opt
.hasFlag(FlagsToExclude
))
434 std::unique_ptr
<Arg
> OptTable::internalParseOneArg(
435 const ArgList
&Args
, unsigned &Index
,
436 std::function
<bool(const Option
&)> ExcludeOption
) const {
437 unsigned Prev
= Index
;
438 StringRef Str
= Args
.getArgString(Index
);
440 // Anything that doesn't start with PrefixesUnion is an input, as is '-'
442 if (isInput(PrefixesUnion
, Str
))
443 return std::make_unique
<Arg
>(getOption(InputOptionID
), Str
, Index
++,
446 const Info
*Start
= OptionInfos
.data() + FirstSearchableIndex
;
447 const Info
*End
= OptionInfos
.data() + OptionInfos
.size();
448 StringRef Name
= Str
.ltrim(PrefixChars
);
450 // Search for the first next option which could be a prefix.
452 std::lower_bound(Start
, End
, Name
, OptNameLess(StrTable
, PrefixesTable
));
454 // Options are stored in sorted order, with '\0' at the end of the
455 // alphabet. Since the only options which can accept a string must
456 // prefix it, we iteratively search for the next option which could
459 // FIXME: This is searching much more than necessary, but I am
460 // blanking on the simplest way to make it fast. We can solve this
461 // problem when we move to TableGen.
462 for (; Start
!= End
; ++Start
) {
463 unsigned ArgSize
= 0;
464 // Scan for first option which is a proper prefix.
465 for (; Start
!= End
; ++Start
)
467 matchOption(StrTable
, PrefixesTable
, Start
, Str
, IgnoreCase
)))
472 Option
Opt(Start
, this);
474 if (ExcludeOption(Opt
))
477 // See if this option matches.
478 if (std::unique_ptr
<Arg
> A
=
479 Opt
.accept(Args
, StringRef(Args
.getArgString(Index
), ArgSize
),
480 /*GroupedShortOption=*/false, Index
))
483 // Otherwise, see if this argument was missing values.
488 // If we failed to find an option and this arg started with /, then it's
489 // probably an input path.
491 return std::make_unique
<Arg
>(getOption(InputOptionID
), Str
, Index
++,
494 return std::make_unique
<Arg
>(getOption(UnknownOptionID
), Str
, Index
++,
498 InputArgList
OptTable::ParseArgs(ArrayRef
<const char *> Args
,
499 unsigned &MissingArgIndex
,
500 unsigned &MissingArgCount
,
501 Visibility VisibilityMask
) const {
502 return internalParseArgs(
503 Args
, MissingArgIndex
, MissingArgCount
,
504 [VisibilityMask
](const Option
&Opt
) {
505 return !Opt
.hasVisibilityFlag(VisibilityMask
);
509 InputArgList
OptTable::ParseArgs(ArrayRef
<const char *> Args
,
510 unsigned &MissingArgIndex
,
511 unsigned &MissingArgCount
,
512 unsigned FlagsToInclude
,
513 unsigned FlagsToExclude
) const {
514 return internalParseArgs(
515 Args
, MissingArgIndex
, MissingArgCount
,
516 [FlagsToInclude
, FlagsToExclude
](const Option
&Opt
) {
517 if (FlagsToInclude
&& !Opt
.hasFlag(FlagsToInclude
))
519 if (Opt
.hasFlag(FlagsToExclude
))
525 InputArgList
OptTable::internalParseArgs(
526 ArrayRef
<const char *> ArgArr
, unsigned &MissingArgIndex
,
527 unsigned &MissingArgCount
,
528 std::function
<bool(const Option
&)> ExcludeOption
) const {
529 InputArgList
Args(ArgArr
.begin(), ArgArr
.end());
531 // FIXME: Handle '@' args (or at least error on them).
533 MissingArgIndex
= MissingArgCount
= 0;
534 unsigned Index
= 0, End
= ArgArr
.size();
535 while (Index
< End
) {
536 // Ingore nullptrs, they are response file's EOL markers
537 if (Args
.getArgString(Index
) == nullptr) {
541 // Ignore empty arguments (other things may still take them as arguments).
542 StringRef Str
= Args
.getArgString(Index
);
548 // In DashDashParsing mode, the first "--" stops option scanning and treats
549 // all subsequent arguments as positional.
550 if (DashDashParsing
&& Str
== "--") {
551 while (++Index
< End
) {
552 Args
.append(new Arg(getOption(InputOptionID
), Str
, Index
,
553 Args
.getArgString(Index
)));
558 unsigned Prev
= Index
;
559 std::unique_ptr
<Arg
> A
= GroupedShortOptions
560 ? parseOneArgGrouped(Args
, Index
)
561 : internalParseOneArg(Args
, Index
, ExcludeOption
);
562 assert((Index
> Prev
|| GroupedShortOptions
) &&
563 "Parser failed to consume argument.");
565 // Check for missing argument error.
567 assert(Index
>= End
&& "Unexpected parser error.");
568 assert(Index
- Prev
- 1 && "No missing arguments!");
569 MissingArgIndex
= Prev
;
570 MissingArgCount
= Index
- Prev
- 1;
574 Args
.append(A
.release());
580 InputArgList
OptTable::parseArgs(int Argc
, char *const *Argv
,
581 OptSpecifier Unknown
, StringSaver
&Saver
,
582 std::function
<void(StringRef
)> ErrorFn
) const {
583 SmallVector
<const char *, 0> NewArgv
;
584 // The environment variable specifies initial options which can be overridden
585 // by commnad line options.
586 cl::expandResponseFiles(Argc
, Argv
, EnvVar
, Saver
, NewArgv
);
589 opt::InputArgList Args
= ParseArgs(ArrayRef(NewArgv
), MAI
, MAC
);
591 ErrorFn((Twine(Args
.getArgString(MAI
)) + ": missing argument").str());
593 // For each unknwon option, call ErrorFn with a formatted error message. The
594 // message includes a suggested alternative option spelling if available.
596 for (const opt::Arg
*A
: Args
.filtered(Unknown
)) {
597 std::string Spelling
= A
->getAsString(Args
);
598 if (findNearest(Spelling
, Nearest
) > 1)
599 ErrorFn("unknown argument '" + Spelling
+ "'");
601 ErrorFn("unknown argument '" + Spelling
+ "', did you mean '" + Nearest
+
607 static std::string
getOptionHelpName(const OptTable
&Opts
, OptSpecifier Id
) {
608 const Option O
= Opts
.getOption(Id
);
609 std::string Name
= O
.getPrefixedName().str();
611 // Add metavar, if used.
612 switch (O
.getKind()) {
613 case Option::GroupClass
: case Option::InputClass
: case Option::UnknownClass
:
614 llvm_unreachable("Invalid option with help text.");
616 case Option::MultiArgClass
:
617 if (const char *MetaVarName
= Opts
.getOptionMetaVar(Id
)) {
618 // For MultiArgs, metavar is full list of all argument names.
623 // For MultiArgs<N>, if metavar not supplied, print <value> N times.
624 for (unsigned i
=0, e
=O
.getNumArgs(); i
< e
; ++i
) {
630 case Option::FlagClass
:
633 case Option::ValuesClass
:
636 case Option::SeparateClass
: case Option::JoinedOrSeparateClass
:
637 case Option::RemainingArgsClass
: case Option::RemainingArgsJoinedClass
:
640 case Option::JoinedClass
: case Option::CommaJoinedClass
:
641 case Option::JoinedAndSeparateClass
:
642 if (const char *MetaVarName
= Opts
.getOptionMetaVar(Id
))
659 static void PrintHelpOptionList(raw_ostream
&OS
, StringRef Title
,
660 std::vector
<OptionInfo
> &OptionHelp
) {
661 OS
<< Title
<< ":\n";
663 // Find the maximum option length.
664 unsigned OptionFieldWidth
= 0;
665 for (const OptionInfo
&Opt
: OptionHelp
) {
666 // Limit the amount of padding we are willing to give up for alignment.
667 unsigned Length
= Opt
.Name
.size();
669 OptionFieldWidth
= std::max(OptionFieldWidth
, Length
);
672 const unsigned InitialPad
= 2;
673 for (const OptionInfo
&Opt
: OptionHelp
) {
674 const std::string
&Option
= Opt
.Name
;
675 int Pad
= OptionFieldWidth
+ InitialPad
;
676 int FirstLinePad
= OptionFieldWidth
- int(Option
.size());
677 OS
.indent(InitialPad
) << Option
;
679 // Break on long option names.
680 if (FirstLinePad
< 0) {
682 FirstLinePad
= OptionFieldWidth
+ InitialPad
;
686 SmallVector
<StringRef
> Lines
;
687 Opt
.HelpText
.split(Lines
, '\n');
688 assert(Lines
.size() && "Expected at least the first line in the help text");
689 auto *LinesIt
= Lines
.begin();
690 OS
.indent(FirstLinePad
+ 1) << *LinesIt
<< '\n';
691 while (Lines
.end() != ++LinesIt
)
692 OS
.indent(Pad
+ 1) << *LinesIt
<< '\n';
696 static const char *getOptionHelpGroup(const OptTable
&Opts
, OptSpecifier Id
) {
697 unsigned GroupID
= Opts
.getOptionGroupID(Id
);
699 // If not in a group, return the default help group.
703 // Abuse the help text of the option groups to store the "help group"
706 // FIXME: Split out option groups.
707 if (const char *GroupHelp
= Opts
.getOptionHelpText(GroupID
))
710 // Otherwise keep looking.
711 return getOptionHelpGroup(Opts
, GroupID
);
714 void OptTable::printHelp(raw_ostream
&OS
, const char *Usage
, const char *Title
,
715 bool ShowHidden
, bool ShowAllAliases
,
716 Visibility VisibilityMask
) const {
717 return internalPrintHelp(
718 OS
, Usage
, Title
, ShowHidden
, ShowAllAliases
,
719 [VisibilityMask
](const Info
&CandidateInfo
) -> bool {
720 return (CandidateInfo
.Visibility
& VisibilityMask
) == 0;
725 void OptTable::printHelp(raw_ostream
&OS
, const char *Usage
, const char *Title
,
726 unsigned FlagsToInclude
, unsigned FlagsToExclude
,
727 bool ShowAllAliases
) const {
728 bool ShowHidden
= !(FlagsToExclude
& HelpHidden
);
729 FlagsToExclude
&= ~HelpHidden
;
730 return internalPrintHelp(
731 OS
, Usage
, Title
, ShowHidden
, ShowAllAliases
,
732 [FlagsToInclude
, FlagsToExclude
](const Info
&CandidateInfo
) {
733 if (FlagsToInclude
&& !(CandidateInfo
.Flags
& FlagsToInclude
))
735 if (CandidateInfo
.Flags
& FlagsToExclude
)
742 void OptTable::internalPrintHelp(
743 raw_ostream
&OS
, const char *Usage
, const char *Title
, bool ShowHidden
,
744 bool ShowAllAliases
, std::function
<bool(const Info
&)> ExcludeOption
,
745 Visibility VisibilityMask
) const {
746 OS
<< "OVERVIEW: " << Title
<< "\n\n";
747 OS
<< "USAGE: " << Usage
<< "\n\n";
749 // Render help text into a map of group-name to a list of (option, help)
751 std::map
<std::string
, std::vector
<OptionInfo
>> GroupedOptionHelp
;
753 for (unsigned Id
= 1, e
= getNumOptions() + 1; Id
!= e
; ++Id
) {
754 // FIXME: Split out option groups.
755 if (getOptionKind(Id
) == Option::GroupClass
)
758 const Info
&CandidateInfo
= getInfo(Id
);
759 if (!ShowHidden
&& (CandidateInfo
.Flags
& opt::HelpHidden
))
762 if (ExcludeOption(CandidateInfo
))
765 // If an alias doesn't have a help text, show a help text for the aliased
767 const char *HelpText
= getOptionHelpText(Id
, VisibilityMask
);
768 if (!HelpText
&& ShowAllAliases
) {
769 const Option Alias
= getOption(Id
).getAlias();
771 HelpText
= getOptionHelpText(Alias
.getID(), VisibilityMask
);
774 if (HelpText
&& (strlen(HelpText
) != 0)) {
775 const char *HelpGroup
= getOptionHelpGroup(*this, Id
);
776 const std::string
&OptName
= getOptionHelpName(*this, Id
);
777 GroupedOptionHelp
[HelpGroup
].push_back({OptName
, HelpText
});
781 for (auto& OptionGroup
: GroupedOptionHelp
) {
782 if (OptionGroup
.first
!= GroupedOptionHelp
.begin()->first
)
784 PrintHelpOptionList(OS
, OptionGroup
.first
, OptionGroup
.second
);
790 GenericOptTable::GenericOptTable(const char *StrTable
,
791 ArrayRef
<unsigned> PrefixesTable
,
792 ArrayRef
<Info
> OptionInfos
, bool IgnoreCase
)
793 : OptTable(StrTable
, PrefixesTable
, OptionInfos
, IgnoreCase
) {
795 std::set
<StringRef
> TmpPrefixesUnion
;
796 for (auto const &Info
: OptionInfos
.drop_front(FirstSearchableIndex
))
797 for (unsigned PrefixOffset
: Info
.getPrefixOffsets(PrefixesTable
))
798 TmpPrefixesUnion
.insert(StringRef(&StrTable
[PrefixOffset
]));
799 PrefixesUnion
.append(TmpPrefixesUnion
.begin(), TmpPrefixesUnion
.end());