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/ADT/STLExtras.h"
10 #include "llvm/ADT/StringRef.h"
11 #include "llvm/ADT/StringSet.h"
12 #include "llvm/Option/Arg.h"
13 #include "llvm/Option/ArgList.h"
14 #include "llvm/Option/Option.h"
15 #include "llvm/Option/OptSpecifier.h"
16 #include "llvm/Option/OptTable.h"
17 #include "llvm/Support/Compiler.h"
18 #include "llvm/Support/ErrorHandling.h"
19 #include "llvm/Support/raw_ostream.h"
30 using namespace llvm::opt
;
35 // Ordering on Info. The ordering is *almost* case-insensitive lexicographic,
36 // with an exception. '\0' comes at the end of the alphabet instead of the
37 // beginning (thus options precede any other options which prefix them).
38 static int StrCmpOptionNameIgnoreCase(const char *A
, const char *B
) {
39 const char *X
= A
, *Y
= B
;
40 char a
= tolower(*A
), b
= tolower(*B
);
49 if (a
== '\0') // A is a prefix of B.
51 if (b
== '\0') // B is a prefix of A.
54 // Otherwise lexicographic.
55 return (a
< b
) ? -1 : 1;
59 static int StrCmpOptionName(const char *A
, const char *B
) {
60 if (int N
= StrCmpOptionNameIgnoreCase(A
, B
))
65 static inline bool operator<(const OptTable::Info
&A
, const OptTable::Info
&B
) {
69 if (int N
= StrCmpOptionName(A
.Name
, B
.Name
))
72 for (const char * const *APre
= A
.Prefixes
,
73 * const *BPre
= B
.Prefixes
;
74 *APre
!= nullptr && *BPre
!= nullptr; ++APre
, ++BPre
){
75 if (int N
= StrCmpOptionName(*APre
, *BPre
))
79 // Names are the same, check that classes are in order; exactly one
80 // should be joined, and it should succeed the other.
81 assert(((A
.Kind
== Option::JoinedClass
) ^ (B
.Kind
== Option::JoinedClass
)) &&
82 "Unexpected classes for options with same name.");
83 return B
.Kind
== Option::JoinedClass
;
87 // Support lower_bound between info and an option name.
88 static inline bool operator<(const OptTable::Info
&I
, const char *Name
) {
89 return StrCmpOptionNameIgnoreCase(I
.Name
, Name
) < 0;
92 } // end namespace opt
93 } // end namespace llvm
95 OptSpecifier::OptSpecifier(const Option
*Opt
) : ID(Opt
->getID()) {}
97 OptTable::OptTable(ArrayRef
<Info
> OptionInfos
, bool IgnoreCase
)
98 : OptionInfos(OptionInfos
), IgnoreCase(IgnoreCase
) {
99 // Explicitly zero initialize the error to work around a bug in array
100 // value-initialization on MinGW with gcc 4.3.5.
102 // Find start of normal options.
103 for (unsigned i
= 0, e
= getNumOptions(); i
!= e
; ++i
) {
104 unsigned Kind
= getInfo(i
+ 1).Kind
;
105 if (Kind
== Option::InputClass
) {
106 assert(!TheInputOptionID
&& "Cannot have multiple input options!");
107 TheInputOptionID
= getInfo(i
+ 1).ID
;
108 } else if (Kind
== Option::UnknownClass
) {
109 assert(!TheUnknownOptionID
&& "Cannot have multiple unknown options!");
110 TheUnknownOptionID
= getInfo(i
+ 1).ID
;
111 } else if (Kind
!= Option::GroupClass
) {
112 FirstSearchableIndex
= i
;
116 assert(FirstSearchableIndex
!= 0 && "No searchable options?");
119 // Check that everything after the first searchable option is a
120 // regular option class.
121 for (unsigned i
= FirstSearchableIndex
, e
= getNumOptions(); i
!= e
; ++i
) {
122 Option::OptionClass Kind
= (Option::OptionClass
) getInfo(i
+ 1).Kind
;
123 assert((Kind
!= Option::InputClass
&& Kind
!= Option::UnknownClass
&&
124 Kind
!= Option::GroupClass
) &&
125 "Special options should be defined first!");
128 // Check that options are in order.
129 for (unsigned i
= FirstSearchableIndex
+ 1, e
= getNumOptions(); i
!= e
; ++i
){
130 if (!(getInfo(i
) < getInfo(i
+ 1))) {
132 getOption(i
+ 1).dump();
133 llvm_unreachable("Options are not in order!");
139 for (unsigned i
= FirstSearchableIndex
+ 1, e
= getNumOptions() + 1;
141 if (const char *const *P
= getInfo(i
).Prefixes
) {
142 for (; *P
!= nullptr; ++P
) {
143 PrefixesUnion
.insert(*P
);
148 // Build prefix chars.
149 for (StringSet
<>::const_iterator I
= PrefixesUnion
.begin(),
150 E
= PrefixesUnion
.end(); I
!= E
; ++I
) {
151 StringRef Prefix
= I
->getKey();
152 for (StringRef::const_iterator C
= Prefix
.begin(), CE
= Prefix
.end();
154 if (!is_contained(PrefixChars
, *C
))
155 PrefixChars
.push_back(*C
);
159 OptTable::~OptTable() = default;
161 const Option
OptTable::getOption(OptSpecifier Opt
) const {
162 unsigned id
= Opt
.getID();
164 return Option(nullptr, nullptr);
165 assert((unsigned) (id
- 1) < getNumOptions() && "Invalid ID.");
166 return Option(&getInfo(id
), this);
169 static bool isInput(const StringSet
<> &Prefixes
, StringRef Arg
) {
172 for (StringSet
<>::const_iterator I
= Prefixes
.begin(),
173 E
= Prefixes
.end(); I
!= E
; ++I
)
174 if (Arg
.startswith(I
->getKey()))
179 /// \returns Matched size. 0 means no match.
180 static unsigned matchOption(const OptTable::Info
*I
, StringRef Str
,
182 for (const char * const *Pre
= I
->Prefixes
; *Pre
!= nullptr; ++Pre
) {
183 StringRef
Prefix(*Pre
);
184 if (Str
.startswith(Prefix
)) {
185 StringRef Rest
= Str
.substr(Prefix
.size());
186 bool Matched
= IgnoreCase
187 ? Rest
.startswith_lower(I
->Name
)
188 : Rest
.startswith(I
->Name
);
190 return Prefix
.size() + StringRef(I
->Name
).size();
196 // Returns true if one of the Prefixes + In.Names matches Option
197 static bool optionMatches(const OptTable::Info
&In
, StringRef Option
) {
199 for (size_t I
= 0; In
.Prefixes
[I
]; I
++)
200 if (Option
== std::string(In
.Prefixes
[I
]) + In
.Name
)
205 // This function is for flag value completion.
206 // Eg. When "-stdlib=" and "l" was passed to this function, it will return
207 // appropiriate values for stdlib, which starts with l.
208 std::vector
<std::string
>
209 OptTable::suggestValueCompletions(StringRef Option
, StringRef Arg
) const {
210 // Search all options and return possible values.
211 for (size_t I
= FirstSearchableIndex
, E
= OptionInfos
.size(); I
< E
; I
++) {
212 const Info
&In
= OptionInfos
[I
];
213 if (!In
.Values
|| !optionMatches(In
, Option
))
216 SmallVector
<StringRef
, 8> Candidates
;
217 StringRef(In
.Values
).split(Candidates
, ",", -1, false);
219 std::vector
<std::string
> Result
;
220 for (StringRef Val
: Candidates
)
221 if (Val
.startswith(Arg
) && Arg
.compare(Val
))
222 Result
.push_back(Val
);
228 std::vector
<std::string
>
229 OptTable::findByPrefix(StringRef Cur
, unsigned short DisableFlags
) const {
230 std::vector
<std::string
> Ret
;
231 for (size_t I
= FirstSearchableIndex
, E
= OptionInfos
.size(); I
< E
; I
++) {
232 const Info
&In
= OptionInfos
[I
];
233 if (!In
.Prefixes
|| (!In
.HelpText
&& !In
.GroupID
))
235 if (In
.Flags
& DisableFlags
)
238 for (int I
= 0; In
.Prefixes
[I
]; I
++) {
239 std::string S
= std::string(In
.Prefixes
[I
]) + std::string(In
.Name
) + "\t";
242 if (StringRef(S
).startswith(Cur
) && S
.compare(std::string(Cur
) + "\t"))
249 unsigned OptTable::findNearest(StringRef Option
, std::string
&NearestString
,
250 unsigned FlagsToInclude
, unsigned FlagsToExclude
,
251 unsigned MinimumLength
) const {
252 assert(!Option
.empty());
254 // Consider each [option prefix + option name] pair as a candidate, finding
255 // the closest match.
256 unsigned BestDistance
= UINT_MAX
;
257 for (const Info
&CandidateInfo
:
258 ArrayRef
<Info
>(OptionInfos
).drop_front(FirstSearchableIndex
)) {
259 StringRef CandidateName
= CandidateInfo
.Name
;
261 // We can eliminate some option prefix/name pairs as candidates right away:
262 // * Ignore option candidates with empty names, such as "--", or names
263 // that do not meet the minimum length.
264 if (CandidateName
.empty() || CandidateName
.size() < MinimumLength
)
267 // * If FlagsToInclude were specified, ignore options that don't include
269 if (FlagsToInclude
&& !(CandidateInfo
.Flags
& FlagsToInclude
))
271 // * Ignore options that contain the FlagsToExclude.
272 if (CandidateInfo
.Flags
& FlagsToExclude
)
275 // * Ignore positional argument option candidates (which do not
277 if (!CandidateInfo
.Prefixes
)
280 // Now check if the candidate ends with a character commonly used when
281 // delimiting an option from its value, such as '=' or ':'. If it does,
282 // attempt to split the given option based on that delimiter.
284 char Last
= CandidateName
.back();
285 bool CandidateHasDelimiter
= Last
== '=' || Last
== ':';
286 std::string NormalizedName
= Option
;
287 if (CandidateHasDelimiter
) {
288 std::tie(LHS
, RHS
) = Option
.split(Last
);
289 NormalizedName
= LHS
;
290 if (Option
.find(Last
) == LHS
.size())
291 NormalizedName
+= Last
;
294 // Consider each possible prefix for each candidate to find the most
295 // appropriate one. For example, if a user asks for "--helm", suggest
296 // "--help" over "-help".
298 const char *const CandidatePrefix
= CandidateInfo
.Prefixes
[P
]; P
++) {
299 std::string Candidate
= (CandidatePrefix
+ CandidateName
).str();
300 StringRef CandidateRef
= Candidate
;
302 CandidateRef
.edit_distance(NormalizedName
, /*AllowReplacements=*/true,
303 /*MaxEditDistance=*/BestDistance
);
304 if (RHS
.empty() && CandidateHasDelimiter
) {
305 // The Candidate ends with a = or : delimiter, but the option passed in
306 // didn't contain the delimiter (or doesn't have anything after it).
307 // In that case, penalize the correction: `-nodefaultlibs` is more
308 // likely to be a spello for `-nodefaultlib` than `-nodefaultlib:` even
309 // though both have an unmodified editing distance of 1, since the
310 // latter would need an argument.
313 if (Distance
< BestDistance
) {
314 BestDistance
= Distance
;
315 NearestString
= (Candidate
+ RHS
).str();
322 bool OptTable::addValues(const char *Option
, const char *Values
) {
323 for (size_t I
= FirstSearchableIndex
, E
= OptionInfos
.size(); I
< E
; I
++) {
324 Info
&In
= OptionInfos
[I
];
325 if (optionMatches(In
, Option
)) {
333 Arg
*OptTable::ParseOneArg(const ArgList
&Args
, unsigned &Index
,
334 unsigned FlagsToInclude
,
335 unsigned FlagsToExclude
) const {
336 unsigned Prev
= Index
;
337 const char *Str
= Args
.getArgString(Index
);
339 // Anything that doesn't start with PrefixesUnion is an input, as is '-'
341 if (isInput(PrefixesUnion
, Str
))
342 return new Arg(getOption(TheInputOptionID
), Str
, Index
++, Str
);
344 const Info
*Start
= OptionInfos
.data() + FirstSearchableIndex
;
345 const Info
*End
= OptionInfos
.data() + OptionInfos
.size();
346 StringRef Name
= StringRef(Str
).ltrim(PrefixChars
);
348 // Search for the first next option which could be a prefix.
349 Start
= std::lower_bound(Start
, End
, Name
.data());
351 // Options are stored in sorted order, with '\0' at the end of the
352 // alphabet. Since the only options which can accept a string must
353 // prefix it, we iteratively search for the next option which could
356 // FIXME: This is searching much more than necessary, but I am
357 // blanking on the simplest way to make it fast. We can solve this
358 // problem when we move to TableGen.
359 for (; Start
!= End
; ++Start
) {
360 unsigned ArgSize
= 0;
361 // Scan for first option which is a proper prefix.
362 for (; Start
!= End
; ++Start
)
363 if ((ArgSize
= matchOption(Start
, Str
, IgnoreCase
)))
368 Option
Opt(Start
, this);
370 if (FlagsToInclude
&& !Opt
.hasFlag(FlagsToInclude
))
372 if (Opt
.hasFlag(FlagsToExclude
))
375 // See if this option matches.
376 if (Arg
*A
= Opt
.accept(Args
, Index
, ArgSize
))
379 // Otherwise, see if this argument was missing values.
384 // If we failed to find an option and this arg started with /, then it's
385 // probably an input path.
387 return new Arg(getOption(TheInputOptionID
), Str
, Index
++, Str
);
389 return new Arg(getOption(TheUnknownOptionID
), Str
, Index
++, Str
);
392 InputArgList
OptTable::ParseArgs(ArrayRef
<const char *> ArgArr
,
393 unsigned &MissingArgIndex
,
394 unsigned &MissingArgCount
,
395 unsigned FlagsToInclude
,
396 unsigned FlagsToExclude
) const {
397 InputArgList
Args(ArgArr
.begin(), ArgArr
.end());
399 // FIXME: Handle '@' args (or at least error on them).
401 MissingArgIndex
= MissingArgCount
= 0;
402 unsigned Index
= 0, End
= ArgArr
.size();
403 while (Index
< End
) {
404 // Ingore nullptrs, they are response file's EOL markers
405 if (Args
.getArgString(Index
) == nullptr) {
409 // Ignore empty arguments (other things may still take them as arguments).
410 StringRef Str
= Args
.getArgString(Index
);
416 unsigned Prev
= Index
;
417 Arg
*A
= ParseOneArg(Args
, Index
, FlagsToInclude
, FlagsToExclude
);
418 assert(Index
> Prev
&& "Parser failed to consume argument.");
420 // Check for missing argument error.
422 assert(Index
>= End
&& "Unexpected parser error.");
423 assert(Index
- Prev
- 1 && "No missing arguments!");
424 MissingArgIndex
= Prev
;
425 MissingArgCount
= Index
- Prev
- 1;
435 static std::string
getOptionHelpName(const OptTable
&Opts
, OptSpecifier Id
) {
436 const Option O
= Opts
.getOption(Id
);
437 std::string Name
= O
.getPrefixedName();
439 // Add metavar, if used.
440 switch (O
.getKind()) {
441 case Option::GroupClass
: case Option::InputClass
: case Option::UnknownClass
:
442 llvm_unreachable("Invalid option with help text.");
444 case Option::MultiArgClass
:
445 if (const char *MetaVarName
= Opts
.getOptionMetaVar(Id
)) {
446 // For MultiArgs, metavar is full list of all argument names.
451 // For MultiArgs<N>, if metavar not supplied, print <value> N times.
452 for (unsigned i
=0, e
=O
.getNumArgs(); i
< e
; ++i
) {
458 case Option::FlagClass
:
461 case Option::ValuesClass
:
464 case Option::SeparateClass
: case Option::JoinedOrSeparateClass
:
465 case Option::RemainingArgsClass
: case Option::RemainingArgsJoinedClass
:
468 case Option::JoinedClass
: case Option::CommaJoinedClass
:
469 case Option::JoinedAndSeparateClass
:
470 if (const char *MetaVarName
= Opts
.getOptionMetaVar(Id
))
487 static void PrintHelpOptionList(raw_ostream
&OS
, StringRef Title
,
488 std::vector
<OptionInfo
> &OptionHelp
) {
489 OS
<< Title
<< ":\n";
491 // Find the maximum option length.
492 unsigned OptionFieldWidth
= 0;
493 for (unsigned i
= 0, e
= OptionHelp
.size(); i
!= e
; ++i
) {
494 // Limit the amount of padding we are willing to give up for alignment.
495 unsigned Length
= OptionHelp
[i
].Name
.size();
497 OptionFieldWidth
= std::max(OptionFieldWidth
, Length
);
500 const unsigned InitialPad
= 2;
501 for (unsigned i
= 0, e
= OptionHelp
.size(); i
!= e
; ++i
) {
502 const std::string
&Option
= OptionHelp
[i
].Name
;
503 int Pad
= OptionFieldWidth
- int(Option
.size());
504 OS
.indent(InitialPad
) << Option
;
506 // Break on long option names.
509 Pad
= OptionFieldWidth
+ InitialPad
;
511 OS
.indent(Pad
+ 1) << OptionHelp
[i
].HelpText
<< '\n';
515 static const char *getOptionHelpGroup(const OptTable
&Opts
, OptSpecifier Id
) {
516 unsigned GroupID
= Opts
.getOptionGroupID(Id
);
518 // If not in a group, return the default help group.
522 // Abuse the help text of the option groups to store the "help group"
525 // FIXME: Split out option groups.
526 if (const char *GroupHelp
= Opts
.getOptionHelpText(GroupID
))
529 // Otherwise keep looking.
530 return getOptionHelpGroup(Opts
, GroupID
);
533 void OptTable::PrintHelp(raw_ostream
&OS
, const char *Usage
, const char *Title
,
534 bool ShowHidden
, bool ShowAllAliases
) const {
535 PrintHelp(OS
, Usage
, Title
, /*Include*/ 0, /*Exclude*/
536 (ShowHidden
? 0 : HelpHidden
), ShowAllAliases
);
539 void OptTable::PrintHelp(raw_ostream
&OS
, const char *Usage
, const char *Title
,
540 unsigned FlagsToInclude
, unsigned FlagsToExclude
,
541 bool ShowAllAliases
) const {
542 OS
<< "OVERVIEW: " << Title
<< "\n\n";
543 OS
<< "USAGE: " << Usage
<< "\n\n";
545 // Render help text into a map of group-name to a list of (option, help)
547 std::map
<std::string
, std::vector
<OptionInfo
>> GroupedOptionHelp
;
549 for (unsigned Id
= 1, e
= getNumOptions() + 1; Id
!= e
; ++Id
) {
550 // FIXME: Split out option groups.
551 if (getOptionKind(Id
) == Option::GroupClass
)
554 unsigned Flags
= getInfo(Id
).Flags
;
555 if (FlagsToInclude
&& !(Flags
& FlagsToInclude
))
557 if (Flags
& FlagsToExclude
)
560 // If an alias doesn't have a help text, show a help text for the aliased
562 const char *HelpText
= getOptionHelpText(Id
);
563 if (!HelpText
&& ShowAllAliases
) {
564 const Option Alias
= getOption(Id
).getAlias();
566 HelpText
= getOptionHelpText(Alias
.getID());
570 const char *HelpGroup
= getOptionHelpGroup(*this, Id
);
571 const std::string
&OptName
= getOptionHelpName(*this, Id
);
572 GroupedOptionHelp
[HelpGroup
].push_back({OptName
, HelpText
});
576 for (auto& OptionGroup
: GroupedOptionHelp
) {
577 if (OptionGroup
.first
!= GroupedOptionHelp
.begin()->first
)
579 PrintHelpOptionList(OS
, OptionGroup
.first
, OptionGroup
.second
);